Revert "Add Visual Studio specific RC1 binaries."
This reverts commit197d6a579f,2c0fb950bc,62fe5d6c4eandfad09801f8
This commit is contained in:
parent
9bfa74d829
commit
53e59b39c3
|
|
@ -5,17 +5,7 @@
|
||||||
],
|
],
|
||||||
"packages": {
|
"packages": {
|
||||||
"Microsoft.AspNetCore.Razor": { },
|
"Microsoft.AspNetCore.Razor": { },
|
||||||
"Microsoft.AspNet.Razor.VSRC1": {
|
"Microsoft.AspNetCore.Razor.Runtime": { }
|
||||||
"DOC_MISSING": {
|
|
||||||
"lib/net451/Microsoft.AspNet.Razor.VSRC1.dll": "Enter justification"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Microsoft.AspNetCore.Razor.Runtime": { },
|
|
||||||
"Microsoft.AspNet.Razor.Runtime.VSRC1": {
|
|
||||||
"DOC_MISSING": {
|
|
||||||
"lib/net451/Microsoft.AspNet.Razor.Runtime.VSRC1.dll": "Enter justification"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"adx-nonshipping": { // Packages written by the ADX team but that don't ship on NuGet.org (thus, no need to scan anything in them)
|
"adx-nonshipping": { // Packages written by the ADX team but that don't ship on NuGet.org (thus, no need to scan anything in them)
|
||||||
|
|
|
||||||
17
Razor.sln
17
Razor.sln
|
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 14
|
# Visual Studio 14
|
||||||
VisualStudioVersion = 14.0.25123.0
|
VisualStudioVersion = 14.0.24720.0
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3C0D6505-79B3-49D0-B4C3-176F0F1836ED}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3C0D6505-79B3-49D0-B4C3-176F0F1836ED}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|
@ -16,10 +17,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Razor.
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Razor.Test.Sources", "src\Microsoft.AspNetCore.Razor.Test.Sources\Microsoft.AspNetCore.Razor.Test.Sources.xproj", "{E3A2A305-634D-4BA6-95DB-AA06D6C442B0}"
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Razor.Test.Sources", "src\Microsoft.AspNetCore.Razor.Test.Sources\Microsoft.AspNetCore.Razor.Test.Sources.xproj", "{E3A2A305-634D-4BA6-95DB-AA06D6C442B0}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Razor.Runtime.VSRC1", "src\Microsoft.AspNet.Razor.Runtime.VSRC1\Microsoft.AspNet.Razor.Runtime.VSRC1.xproj", "{5E8EC8BB-69B9-43D4-A095-7A06F65838E2}"
|
|
||||||
EndProject
|
|
||||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Razor.VSRC1", "src\Microsoft.AspNet.Razor.VSRC1\Microsoft.AspNet.Razor.VSRC1.xproj", "{AB5ABC37-201B-41FF-9FAF-E948B0D33F5A}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -46,14 +43,6 @@ Global
|
||||||
{E3A2A305-634D-4BA6-95DB-AA06D6C442B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{E3A2A305-634D-4BA6-95DB-AA06D6C442B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{E3A2A305-634D-4BA6-95DB-AA06D6C442B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{E3A2A305-634D-4BA6-95DB-AA06D6C442B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{E3A2A305-634D-4BA6-95DB-AA06D6C442B0}.Release|Any CPU.Build.0 = Release|Any CPU
|
{E3A2A305-634D-4BA6-95DB-AA06D6C442B0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{5E8EC8BB-69B9-43D4-A095-7A06F65838E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{5E8EC8BB-69B9-43D4-A095-7A06F65838E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{5E8EC8BB-69B9-43D4-A095-7A06F65838E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{5E8EC8BB-69B9-43D4-A095-7A06F65838E2}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{AB5ABC37-201B-41FF-9FAF-E948B0D33F5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{AB5ABC37-201B-41FF-9FAF-E948B0D33F5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{AB5ABC37-201B-41FF-9FAF-E948B0D33F5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{AB5ABC37-201B-41FF-9FAF-E948B0D33F5A}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
@ -64,7 +53,5 @@ Global
|
||||||
{D0196096-1B01-4133-AACE-1A10A0F7247C} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
|
{D0196096-1B01-4133-AACE-1A10A0F7247C} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
|
||||||
{0535998A-E32C-4D1A-80D1-0B15A513C471} = {92463391-81BE-462B-AC3C-78C6C760741F}
|
{0535998A-E32C-4D1A-80D1-0B15A513C471} = {92463391-81BE-462B-AC3C-78C6C760741F}
|
||||||
{E3A2A305-634D-4BA6-95DB-AA06D6C442B0} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
|
{E3A2A305-634D-4BA6-95DB-AA06D6C442B0} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
|
||||||
{5E8EC8BB-69B9-43D4-A095-7A06F65838E2} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
|
|
||||||
{AB5ABC37-201B-41FF-9FAF-E948B0D33F5A} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
||||||
|
|
@ -1,125 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using Microsoft.AspNet.Html.Abstractions;
|
|
||||||
using Microsoft.Extensions.WebEncoders;
|
|
||||||
|
|
||||||
namespace Microsoft.Extensions.Internal
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Enumerable object collection which knows how to write itself.
|
|
||||||
/// </summary>
|
|
||||||
[DebuggerDisplay("{DebuggerToString()}")]
|
|
||||||
internal class BufferedHtmlContent : IHtmlContentBuilder
|
|
||||||
{
|
|
||||||
// This is not List<IHtmlContent> because that would lead to wrapping all strings to IHtmlContent
|
|
||||||
// which is not space performant.
|
|
||||||
// internal for testing.
|
|
||||||
internal List<object> Entries { get; } = new List<object>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Appends the <see cref="string"/> to the collection.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="unencoded">The <c>string</c> to be appended.</param>
|
|
||||||
/// <returns>A reference to this instance after the Append operation has completed.</returns>
|
|
||||||
public IHtmlContentBuilder Append(string unencoded)
|
|
||||||
{
|
|
||||||
Entries.Add(unencoded);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Appends a <see cref="IHtmlContent"/> to the collection.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="htmlContent">The <see cref="IHtmlContent"/> to be appended.</param>
|
|
||||||
/// <returns>A reference to this instance after the Append operation has completed.</returns>
|
|
||||||
public IHtmlContentBuilder Append(IHtmlContent htmlContent)
|
|
||||||
{
|
|
||||||
Entries.Add(htmlContent);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Appends the HTML encoded <see cref="string"/> to the collection.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encoded">The HTML encoded <c>string</c> to be appended.</param>
|
|
||||||
/// <returns>A reference to this instance after the Append operation has completed.</returns>
|
|
||||||
public IHtmlContentBuilder AppendHtml(string encoded)
|
|
||||||
{
|
|
||||||
Entries.Add(new HtmlEncodedString(encoded));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Removes all the entries from the collection.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A reference to this instance after the Clear operation has completed.</returns>
|
|
||||||
public IHtmlContentBuilder Clear()
|
|
||||||
{
|
|
||||||
Entries.Clear();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void WriteTo(TextWriter writer, IHtmlEncoder encoder)
|
|
||||||
{
|
|
||||||
if (writer == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(writer));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (encoder == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(encoder));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var entry in Entries)
|
|
||||||
{
|
|
||||||
if (entry == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var entryAsString = entry as string;
|
|
||||||
if (entryAsString != null)
|
|
||||||
{
|
|
||||||
encoder.HtmlEncode(entryAsString, writer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Only string, IHtmlContent values can be added to the buffer.
|
|
||||||
((IHtmlContent)entry).WriteTo(writer, encoder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string DebuggerToString()
|
|
||||||
{
|
|
||||||
using (var writer = new StringWriter())
|
|
||||||
{
|
|
||||||
WriteTo(writer, HtmlEncoder.Default);
|
|
||||||
return writer.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class HtmlEncodedString : IHtmlContent
|
|
||||||
{
|
|
||||||
public static readonly IHtmlContent NewLine = new HtmlEncodedString(Environment.NewLine);
|
|
||||||
|
|
||||||
private readonly string _value;
|
|
||||||
|
|
||||||
public HtmlEncodedString(string value)
|
|
||||||
{
|
|
||||||
_value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteTo(TextWriter writer, IHtmlEncoder encoder)
|
|
||||||
{
|
|
||||||
writer.Write(_value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace Microsoft.Extensions.Internal
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Helper related to generic interface definitions and implementing classes.
|
|
||||||
/// </summary>
|
|
||||||
internal static class ClosedGenericMatcher
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Determine whether <paramref name="queryType"/> is or implements a closed generic <see cref="Type"/>
|
|
||||||
/// created from <paramref name="interfaceType"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="queryType">The <see cref="Type"/> of interest.</param>
|
|
||||||
/// <param name="interfaceType">The open generic <see cref="Type"/> to match. Usually an interface.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// The closed generic <see cref="Type"/> created from <paramref name="interfaceType"/> that
|
|
||||||
/// <paramref name="queryType"/> is or implements. <c>null</c> if the two <see cref="Type"/>s have no such
|
|
||||||
/// relationship.
|
|
||||||
/// </returns>
|
|
||||||
/// <remarks>
|
|
||||||
/// This method will return <paramref name="queryType"/> if <paramref name="interfaceType"/> is
|
|
||||||
/// <c>typeof(KeyValuePair{,})</c>, and <paramref name="queryType"/> is
|
|
||||||
/// <c>typeof(KeyValuePair{string, object})</c>.
|
|
||||||
/// </remarks>
|
|
||||||
public static Type ExtractGenericInterface(Type queryType, Type interfaceType)
|
|
||||||
{
|
|
||||||
if (queryType == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(queryType));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interfaceType == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(interfaceType));
|
|
||||||
}
|
|
||||||
|
|
||||||
Func<Type, bool> matchesInterface =
|
|
||||||
type => type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == interfaceType;
|
|
||||||
if (matchesInterface(queryType))
|
|
||||||
{
|
|
||||||
// Checked type matches (i.e. is a closed generic type created from) the open generic type.
|
|
||||||
return queryType;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise check all interfaces the type implements for a match.
|
|
||||||
return queryType.GetTypeInfo().ImplementedInterfaces.FirstOrDefault(matchesInterface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,155 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.Extensions.Internal
|
|
||||||
{
|
|
||||||
internal class CopyOnWriteDictionary<TKey, TValue> : IDictionary<TKey, TValue>
|
|
||||||
{
|
|
||||||
private readonly IDictionary<TKey, TValue> _sourceDictionary;
|
|
||||||
private readonly IEqualityComparer<TKey> _comparer;
|
|
||||||
private IDictionary<TKey, TValue> _innerDictionary;
|
|
||||||
|
|
||||||
public CopyOnWriteDictionary(
|
|
||||||
IDictionary<TKey, TValue> sourceDictionary,
|
|
||||||
IEqualityComparer<TKey> comparer)
|
|
||||||
{
|
|
||||||
if (sourceDictionary == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(sourceDictionary));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (comparer == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(comparer));
|
|
||||||
}
|
|
||||||
|
|
||||||
_sourceDictionary = sourceDictionary;
|
|
||||||
_comparer = comparer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IDictionary<TKey, TValue> ReadDictionary
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _innerDictionary ?? _sourceDictionary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IDictionary<TKey, TValue> WriteDictionary
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_innerDictionary == null)
|
|
||||||
{
|
|
||||||
_innerDictionary = new Dictionary<TKey, TValue>(_sourceDictionary,
|
|
||||||
_comparer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _innerDictionary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual ICollection<TKey> Keys
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return ReadDictionary.Keys;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual ICollection<TValue> Values
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return ReadDictionary.Values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return ReadDictionary.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool IsReadOnly
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual TValue this[TKey key]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return ReadDictionary[key];
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
WriteDictionary[key] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool ContainsKey(TKey key)
|
|
||||||
{
|
|
||||||
return ReadDictionary.ContainsKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Add(TKey key, TValue value)
|
|
||||||
{
|
|
||||||
WriteDictionary.Add(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool Remove(TKey key)
|
|
||||||
{
|
|
||||||
return WriteDictionary.Remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool TryGetValue(TKey key, out TValue value)
|
|
||||||
{
|
|
||||||
return ReadDictionary.TryGetValue(key, out value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Add(KeyValuePair<TKey, TValue> item)
|
|
||||||
{
|
|
||||||
WriteDictionary.Add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Clear()
|
|
||||||
{
|
|
||||||
WriteDictionary.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool Contains(KeyValuePair<TKey, TValue> item)
|
|
||||||
{
|
|
||||||
return ReadDictionary.Contains(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
|
||||||
{
|
|
||||||
ReadDictionary.CopyTo(array, arrayIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove(KeyValuePair<TKey, TValue> item)
|
|
||||||
{
|
|
||||||
return WriteDictionary.Remove(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
|
||||||
{
|
|
||||||
return ReadDictionary.GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,166 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.Extensions.Internal
|
|
||||||
{
|
|
||||||
internal struct CopyOnWriteDictionaryHolder<TKey, TValue>
|
|
||||||
{
|
|
||||||
private readonly Dictionary<TKey, TValue> _source;
|
|
||||||
private Dictionary<TKey, TValue> _copy;
|
|
||||||
|
|
||||||
public CopyOnWriteDictionaryHolder(Dictionary<TKey, TValue> source)
|
|
||||||
{
|
|
||||||
if (source == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(source));
|
|
||||||
}
|
|
||||||
|
|
||||||
_source = source;
|
|
||||||
_copy = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CopyOnWriteDictionaryHolder(CopyOnWriteDictionaryHolder<TKey, TValue> source)
|
|
||||||
{
|
|
||||||
_source = source._copy ?? source._source;
|
|
||||||
_copy = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasBeenCopied => _copy != null;
|
|
||||||
|
|
||||||
public Dictionary<TKey, TValue> ReadDictionary
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_copy != null)
|
|
||||||
{
|
|
||||||
return _copy;
|
|
||||||
}
|
|
||||||
else if (_source != null)
|
|
||||||
{
|
|
||||||
return _source;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Default-Constructor case
|
|
||||||
_copy = new Dictionary<TKey, TValue>();
|
|
||||||
return _copy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dictionary<TKey, TValue> WriteDictionary
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_copy == null && _source == null)
|
|
||||||
{
|
|
||||||
// Default-Constructor case
|
|
||||||
_copy = new Dictionary<TKey, TValue>();
|
|
||||||
}
|
|
||||||
else if (_copy == null)
|
|
||||||
{
|
|
||||||
_copy = new Dictionary<TKey, TValue>(_source, _source.Comparer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _copy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dictionary<TKey, TValue>.KeyCollection Keys
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return ReadDictionary.Keys;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dictionary<TKey, TValue>.ValueCollection Values
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return ReadDictionary.Values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return ReadDictionary.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsReadOnly
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TValue this[TKey key]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return ReadDictionary[key];
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
WriteDictionary[key] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ContainsKey(TKey key)
|
|
||||||
{
|
|
||||||
return ReadDictionary.ContainsKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(TKey key, TValue value)
|
|
||||||
{
|
|
||||||
WriteDictionary.Add(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove(TKey key)
|
|
||||||
{
|
|
||||||
return WriteDictionary.Remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetValue(TKey key, out TValue value)
|
|
||||||
{
|
|
||||||
return ReadDictionary.TryGetValue(key, out value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(KeyValuePair<TKey, TValue> item)
|
|
||||||
{
|
|
||||||
((ICollection<KeyValuePair<TKey, TValue>>)WriteDictionary).Add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
WriteDictionary.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(KeyValuePair<TKey, TValue> item)
|
|
||||||
{
|
|
||||||
return ((ICollection<KeyValuePair<TKey, TValue>>)ReadDictionary).Contains(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
|
||||||
{
|
|
||||||
((ICollection<KeyValuePair<TKey, TValue>>)ReadDictionary).CopyTo(array, arrayIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove(KeyValuePair<TKey, TValue> item)
|
|
||||||
{
|
|
||||||
return ((ICollection<KeyValuePair<TKey, TValue>>)WriteDictionary).Remove(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dictionary<TKey, TValue>.Enumerator GetEnumerator()
|
|
||||||
{
|
|
||||||
return ReadDictionary.GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
|
||||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
|
||||||
<PropertyGroup Label="Globals">
|
|
||||||
<ProjectGuid>5e8ec8bb-69b9-43d4-a095-7a06f65838e2</ProjectGuid>
|
|
||||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
|
||||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup>
|
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
|
||||||
</Project>
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Resources;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
[assembly: AssemblyMetadata("Serviceable", "True")]
|
|
||||||
[assembly: NeutralResourcesLanguage("en-us")]
|
|
||||||
[assembly: AssemblyCompany("Microsoft Corporation.")]
|
|
||||||
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
|
|
||||||
[assembly: AssemblyProduct("Microsoft ASP.NET Core")]
|
|
||||||
|
|
@ -1,478 +0,0 @@
|
||||||
// <auto-generated />
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime
|
|
||||||
{
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Resources;
|
|
||||||
|
|
||||||
internal static class Resources
|
|
||||||
{
|
|
||||||
private static readonly ResourceManager _resourceManager
|
|
||||||
= new ResourceManager("Microsoft.AspNet.Razor.Runtime.VSRC1.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper directive look up text '{0}'. The correct look up text format is: "typeName, assemblyName".
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorResolver_InvalidTagHelperLookupText
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorResolver_InvalidTagHelperLookupText"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper directive look up text '{0}'. The correct look up text format is: "typeName, assemblyName".
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorResolver_InvalidTagHelperLookupText(object p0)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorResolver_InvalidTagHelperLookupText"), p0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Cannot resolve TagHelper containing assembly '{0}'. Error: {1}
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperTypeResolver_CannotResolveTagHelperAssembly
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperTypeResolver_CannotResolveTagHelperAssembly"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Cannot resolve TagHelper containing assembly '{0}'. Error: {1}
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperTypeResolver_CannotResolveTagHelperAssembly(object p0, object p1)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperTypeResolver_CannotResolveTagHelperAssembly"), p0, p1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tag helper directive assembly name cannot be null or empty.
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperTypeResolver_TagHelperAssemblyNameCannotBeEmptyOrNull
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperTypeResolver_TagHelperAssemblyNameCannotBeEmptyOrNull"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tag helper directive assembly name cannot be null or empty.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperTypeResolver_TagHelperAssemblyNameCannotBeEmptyOrNull()
|
|
||||||
{
|
|
||||||
return GetString("TagHelperTypeResolver_TagHelperAssemblyNameCannotBeEmptyOrNull");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Must call '{2}.{1}' before calling '{2}.{0}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string ScopeManager_EndCannotBeCalledWithoutACallToBegin
|
|
||||||
{
|
|
||||||
get { return GetString("ScopeManager_EndCannotBeCalledWithoutACallToBegin"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Must call '{2}.{1}' before calling '{2}.{0}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatScopeManager_EndCannotBeCalledWithoutACallToBegin(object p0, object p1, object p2)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("ScopeManager_EndCannotBeCalledWithoutACallToBegin"), p0, p1, p2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// {0} name cannot be null or whitespace.
|
|
||||||
/// </summary>
|
|
||||||
internal static string HtmlTargetElementAttribute_NameCannotBeNullOrWhitespace
|
|
||||||
{
|
|
||||||
get { return GetString("HtmlTargetElementAttribute_NameCannotBeNullOrWhitespace"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// {0} name cannot be null or whitespace.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatHtmlTargetElementAttribute_NameCannotBeNullOrWhitespace(object p0)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("HtmlTargetElementAttribute_NameCannotBeNullOrWhitespace"), p0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The value cannot be null or empty.
|
|
||||||
/// </summary>
|
|
||||||
internal static string ArgumentCannotBeNullOrEmpty
|
|
||||||
{
|
|
||||||
get { return GetString("ArgumentCannotBeNullOrEmpty"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The value cannot be null or empty.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatArgumentCannotBeNullOrEmpty()
|
|
||||||
{
|
|
||||||
return GetString("ArgumentCannotBeNullOrEmpty");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encountered an unexpected error when attempting to resolve tag helper directive '{0}' with value '{1}'. Error: {2}
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorResolver_EncounteredUnexpectedError
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorResolver_EncounteredUnexpectedError"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encountered an unexpected error when attempting to resolve tag helper directive '{0}' with value '{1}'. Error: {2}
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorResolver_EncounteredUnexpectedError(object p0, object p1, object p2)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorResolver_EncounteredUnexpectedError"), p0, p1, p2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tag helpers cannot target {0} name '{1}' because it contains a '{2}' character.
|
|
||||||
/// </summary>
|
|
||||||
internal static string HtmlTargetElementAttribute_InvalidName
|
|
||||||
{
|
|
||||||
get { return GetString("HtmlTargetElementAttribute_InvalidName"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tag helpers cannot target {0} name '{1}' because it contains a '{2}' character.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatHtmlTargetElementAttribute_InvalidName(object p0, object p1, object p2)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("HtmlTargetElementAttribute_InvalidName"), p0, p1, p2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper directive '{0}'. Cannot have multiple '{0}' directives on a page.
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorResolver_InvalidTagHelperDirective
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorResolver_InvalidTagHelperDirective"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper directive '{0}'. Cannot have multiple '{0}' directives on a page.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorResolver_InvalidTagHelperDirective(object p0)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorResolver_InvalidTagHelperDirective"), p0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper directive '{0}' value. '{1}' is not allowed in prefix '{2}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorResolver_InvalidTagHelperPrefixValue
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorResolver_InvalidTagHelperPrefixValue"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper directive '{0}' value. '{1}' is not allowed in prefix '{2}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorResolver_InvalidTagHelperPrefixValue(object p0, object p1, object p2)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorResolver_InvalidTagHelperPrefixValue"), p0, p1, p2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorFactory_Attribute
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorFactory_Attribute"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorFactory_Attribute()
|
|
||||||
{
|
|
||||||
return GetString("TagHelperDescriptorFactory_Attribute");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// name
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorFactory_Name
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorFactory_Name"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// name
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorFactory_Name()
|
|
||||||
{
|
|
||||||
return GetString("TagHelperDescriptorFactory_Name");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// prefix
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorFactory_Prefix
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorFactory_Prefix"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// prefix
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorFactory_Prefix()
|
|
||||||
{
|
|
||||||
return GetString("TagHelperDescriptorFactory_Prefix");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tag
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorFactory_Tag
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorFactory_Tag"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tag
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorFactory_Tag()
|
|
||||||
{
|
|
||||||
return GetString("TagHelperDescriptorFactory_Tag");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper bound property '{0}.{1}'. An '{2}' must not be associated with a property with no public setter unless its type implements '{3}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorFactory_InvalidAttributeNameAttribute
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorFactory_InvalidAttributeNameAttribute"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper bound property '{0}.{1}'. An '{2}' must not be associated with a property with no public setter unless its type implements '{3}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorFactory_InvalidAttributeNameAttribute(object p0, object p1, object p2, object p3)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidAttributeNameAttribute"), p0, p1, p2, p3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with {2} '{3}' because {2} contains a '{4}' character.
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorFactory_InvalidAttributeNameOrPrefixCharacter
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorFactory_InvalidAttributeNameOrPrefixCharacter"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with {2} '{3}' because {2} contains a '{4}' character.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorFactory_InvalidAttributeNameOrPrefixCharacter(object p0, object p1, object p2, object p3, object p4)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidAttributeNameOrPrefixCharacter"), p0, p1, p2, p3, p4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with {2} '{3}' because {2} starts with '{4}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorFactory_InvalidAttributeNameOrPrefixStart
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorFactory_InvalidAttributeNameOrPrefixStart"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with {2} '{3}' because {2} starts with '{4}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorFactory_InvalidAttributeNameOrPrefixStart(object p0, object p1, object p2, object p3, object p4)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidAttributeNameOrPrefixStart"), p0, p1, p2, p3, p4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with a whitespace {2}.
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorFactory_InvalidAttributeNameOrPrefixWhitespace
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorFactory_InvalidAttributeNameOrPrefixWhitespace"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with a whitespace {2}.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorFactory_InvalidAttributeNameOrPrefixWhitespace(object p0, object p1, object p2)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidAttributeNameOrPrefixWhitespace"), p0, p1, p2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with a null or empty name.
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorFactory_InvalidAttributeNameNullOrEmpty
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorFactory_InvalidAttributeNameNullOrEmpty"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with a null or empty name.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorFactory_InvalidAttributeNameNullOrEmpty(object p0, object p1)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidAttributeNameNullOrEmpty"), p0, p1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null or empty if property has no public setter.
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorFactory_InvalidAttributeNameNotNullOrEmpty
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorFactory_InvalidAttributeNameNotNullOrEmpty"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null or empty if property has no public setter.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorFactory_InvalidAttributeNameNotNullOrEmpty(object p0, object p1, object p2, object p3)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidAttributeNameNotNullOrEmpty"), p0, p1, p2, p3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must not be null if property has no public setter and its type implements '{4}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorFactory_InvalidAttributePrefixNull
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorFactory_InvalidAttributePrefixNull"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must not be null if property has no public setter and its type implements '{4}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorFactory_InvalidAttributePrefixNull(object p0, object p1, object p2, object p3, object p4)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidAttributePrefixNull"), p0, p1, p2, p3, p4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null unless property type implements '{4}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorFactory_InvalidAttributePrefixNotNull
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorFactory_InvalidAttributePrefixNotNull"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null unless property type implements '{4}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorFactory_InvalidAttributePrefixNotNull(object p0, object p1, object p2, object p3, object p4)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidAttributePrefixNotNull"), p0, p1, p2, p3, p4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Cannot add a '{0}' with a null '{1}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperAttributeList_CannotAddWithNullName
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperAttributeList_CannotAddWithNullName"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Cannot add a '{0}' with a null '{1}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperAttributeList_CannotAddWithNullName(object p0, object p1)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperAttributeList_CannotAddWithNullName"), p0, p1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Cannot add a {0} with inconsistent names. The {1} property '{2}' must match the location '{3}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperAttributeList_CannotAddAttribute
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperAttributeList_CannotAddAttribute"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Cannot add a {0} with inconsistent names. The {1} property '{2}' must match the location '{3}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperAttributeList_CannotAddAttribute(object p0, object p1, object p2, object p3)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperAttributeList_CannotAddAttribute"), p0, p1, p2, p3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid '{0}' tag name '{1}' for tag helper '{2}'. Tag helpers cannot restrict child elements that contain a '{3}' character.
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorFactory_InvalidRestrictChildrenAttributeName
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorFactory_InvalidRestrictChildrenAttributeName"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid '{0}' tag name '{1}' for tag helper '{2}'. Tag helpers cannot restrict child elements that contain a '{3}' character.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorFactory_InvalidRestrictChildrenAttributeName(object p0, object p1, object p2, object p3)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidRestrictChildrenAttributeName"), p0, p1, p2, p3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid '{0}' tag name for tag helper '{1}'. Name cannot be null or whitespace.
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorFactory_InvalidRestrictChildrenAttributeNameNullWhitespace
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorFactory_InvalidRestrictChildrenAttributeNameNullWhitespace"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invalid '{0}' tag name for tag helper '{1}'. Name cannot be null or whitespace.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorFactory_InvalidRestrictChildrenAttributeNameNullWhitespace(object p0, object p1)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidRestrictChildrenAttributeNameNullWhitespace"), p0, p1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Parent Tag
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelperDescriptorFactory_ParentTag
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelperDescriptorFactory_ParentTag"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Parent Tag
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelperDescriptorFactory_ParentTag()
|
|
||||||
{
|
|
||||||
return GetString("TagHelperDescriptorFactory_ParentTag");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Argument must be an instance of '{0}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string ArgumentMustBeAnInstanceOf
|
|
||||||
{
|
|
||||||
get { return GetString("ArgumentMustBeAnInstanceOf"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Argument must be an instance of '{0}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatArgumentMustBeAnInstanceOf(object p0)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("ArgumentMustBeAnInstanceOf"), p0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetString(string name, params string[] formatterNames)
|
|
||||||
{
|
|
||||||
var value = _resourceManager.GetString(name);
|
|
||||||
|
|
||||||
System.Diagnostics.Debug.Assert(value != null);
|
|
||||||
|
|
||||||
if (formatterNames != null)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < formatterNames.Length; i++)
|
|
||||||
{
|
|
||||||
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,204 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<root>
|
|
||||||
<!--
|
|
||||||
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
|
|
||||||
associated with the data types.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
|
||||||
<resheader name="version">2.0</resheader>
|
|
||||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
|
||||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
|
||||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
|
||||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
|
||||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
|
||||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
|
||||||
</data>
|
|
||||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<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
|
|
||||||
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
|
|
||||||
mimetype set.
|
|
||||||
|
|
||||||
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
|
|
||||||
read any of the formats listed below.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
|
||||||
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
|
|
||||||
: 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
|
|
||||||
: using a System.ComponentModel.TypeConverter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
-->
|
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:choice maxOccurs="unbounded">
|
|
||||||
<xsd:element name="metadata">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="assembly">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:attribute name="alias" type="xsd:string" />
|
|
||||||
<xsd:attribute name="name" type="xsd:string" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="data">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="resheader">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:choice>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:schema>
|
|
||||||
<resheader name="resmimetype">
|
|
||||||
<value>text/microsoft-resx</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="version">
|
|
||||||
<value>2.0</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="reader">
|
|
||||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="writer">
|
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
<data name="TagHelperDescriptorResolver_InvalidTagHelperLookupText" xml:space="preserve">
|
|
||||||
<value>Invalid tag helper directive look up text '{0}'. The correct look up text format is: "typeName, assemblyName".</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperTypeResolver_CannotResolveTagHelperAssembly" xml:space="preserve">
|
|
||||||
<value>Cannot resolve TagHelper containing assembly '{0}'. Error: {1}</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperTypeResolver_TagHelperAssemblyNameCannotBeEmptyOrNull" xml:space="preserve">
|
|
||||||
<value>Tag helper directive assembly name cannot be null or empty.</value>
|
|
||||||
</data>
|
|
||||||
<data name="ScopeManager_EndCannotBeCalledWithoutACallToBegin" xml:space="preserve">
|
|
||||||
<value>Must call '{2}.{1}' before calling '{2}.{0}'.</value>
|
|
||||||
</data>
|
|
||||||
<data name="HtmlTargetElementAttribute_NameCannotBeNullOrWhitespace" xml:space="preserve">
|
|
||||||
<value>{0} name cannot be null or whitespace.</value>
|
|
||||||
</data>
|
|
||||||
<data name="ArgumentCannotBeNullOrEmpty" xml:space="preserve">
|
|
||||||
<value>The value cannot be null or empty.</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorResolver_EncounteredUnexpectedError" xml:space="preserve">
|
|
||||||
<value>Encountered an unexpected error when attempting to resolve tag helper directive '{0}' with value '{1}'. Error: {2}</value>
|
|
||||||
</data>
|
|
||||||
<data name="HtmlTargetElementAttribute_InvalidName" xml:space="preserve">
|
|
||||||
<value>Tag helpers cannot target {0} name '{1}' because it contains a '{2}' character.</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorResolver_InvalidTagHelperDirective" xml:space="preserve">
|
|
||||||
<value>Invalid tag helper directive '{0}'. Cannot have multiple '{0}' directives on a page.</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorResolver_InvalidTagHelperPrefixValue" xml:space="preserve">
|
|
||||||
<value>Invalid tag helper directive '{0}' value. '{1}' is not allowed in prefix '{2}'.</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorFactory_Attribute" xml:space="preserve">
|
|
||||||
<value>Attribute</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorFactory_Name" xml:space="preserve">
|
|
||||||
<value>name</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorFactory_Prefix" xml:space="preserve">
|
|
||||||
<value>prefix</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorFactory_Tag" xml:space="preserve">
|
|
||||||
<value>Tag</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorFactory_InvalidAttributeNameAttribute" xml:space="preserve">
|
|
||||||
<value>Invalid tag helper bound property '{0}.{1}'. An '{2}' must not be associated with a property with no public setter unless its type implements '{3}'.</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorFactory_InvalidAttributeNameOrPrefixCharacter" xml:space="preserve">
|
|
||||||
<value>Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with {2} '{3}' because {2} contains a '{4}' character.</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorFactory_InvalidAttributeNameOrPrefixStart" xml:space="preserve">
|
|
||||||
<value>Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with {2} '{3}' because {2} starts with '{4}'.</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorFactory_InvalidAttributeNameOrPrefixWhitespace" xml:space="preserve">
|
|
||||||
<value>Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with a whitespace {2}.</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorFactory_InvalidAttributeNameNullOrEmpty" xml:space="preserve">
|
|
||||||
<value>Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with a null or empty name.</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorFactory_InvalidAttributeNameNotNullOrEmpty" xml:space="preserve">
|
|
||||||
<value>Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null or empty if property has no public setter.</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorFactory_InvalidAttributePrefixNull" xml:space="preserve">
|
|
||||||
<value>Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must not be null if property has no public setter and its type implements '{4}'.</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorFactory_InvalidAttributePrefixNotNull" xml:space="preserve">
|
|
||||||
<value>Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null unless property type implements '{4}'.</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperAttributeList_CannotAddWithNullName" xml:space="preserve">
|
|
||||||
<value>Cannot add a '{0}' with a null '{1}'.</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperAttributeList_CannotAddAttribute" xml:space="preserve">
|
|
||||||
<value>Cannot add a {0} with inconsistent names. The {1} property '{2}' must match the location '{3}'.</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorFactory_InvalidRestrictChildrenAttributeName" xml:space="preserve">
|
|
||||||
<value>Invalid '{0}' tag name '{1}' for tag helper '{2}'. Tag helpers cannot restrict child elements that contain a '{3}' character.</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorFactory_InvalidRestrictChildrenAttributeNameNullWhitespace" xml:space="preserve">
|
|
||||||
<value>Invalid '{0}' tag name for tag helper '{1}'. Name cannot be null or whitespace.</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelperDescriptorFactory_ParentTag" xml:space="preserve">
|
|
||||||
<value>Parent Tag</value>
|
|
||||||
</data>
|
|
||||||
<data name="ArgumentMustBeAnInstanceOf" xml:space="preserve">
|
|
||||||
<value>Argument must be an instance of '{0}'.</value>
|
|
||||||
</data>
|
|
||||||
</root>
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|
||||||
{
|
|
||||||
internal static class Constants
|
|
||||||
{
|
|
||||||
public static readonly TimeSpan RegexMatchTimeout = TimeSpan.FromSeconds(10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Metadata common to types and properties.
|
|
||||||
/// </summary>
|
|
||||||
public interface IMemberInfo
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the name.
|
|
||||||
/// </summary>
|
|
||||||
string Name { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieves a collection of custom <see cref="Attribute"/>s of type <typeparamref name="TAttribute"/> applied
|
|
||||||
/// to this instance of <see cref="IMemberInfo"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TAttribute">The type of <see cref="Attribute"/> to search for.</typeparam>
|
|
||||||
/// <returns>A sequence of custom <see cref="Attribute"/>s of type
|
|
||||||
/// <typeparamref name="TAttribute"/>.</returns>
|
|
||||||
/// <remarks>Result not include inherited <see cref="Attribute"/>s.</remarks>
|
|
||||||
IEnumerable<TAttribute> GetCustomAttributes<TAttribute>()
|
|
||||||
where TAttribute : Attribute;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Contains property metadata.
|
|
||||||
/// </summary>
|
|
||||||
public interface IPropertyInfo : IMemberInfo
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether this property has a public getter.
|
|
||||||
/// </summary>
|
|
||||||
bool HasPublicGetter { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether this property has a public setter.
|
|
||||||
/// </summary>
|
|
||||||
bool HasPublicSetter { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="ITypeInfo"/> of the property.
|
|
||||||
/// </summary>
|
|
||||||
ITypeInfo PropertyType { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Contains type metadata.
|
|
||||||
/// </summary>
|
|
||||||
public interface ITypeInfo : IMemberInfo, IEquatable<ITypeInfo>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Fully qualified name of the type.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// On CoreCLR, some BCL types get type forwarded to the full desktop framework implementations at
|
|
||||||
/// runtime. For e.g. we compile against System.String in System.Runtime which is type forwarded to
|
|
||||||
/// mscorlib at runtime. Consequently for generic types where the <see cref="FullName"/> includes the assembly
|
|
||||||
/// qualified name of generic parameters, FullNames would not match.
|
|
||||||
/// Use <see cref="IEquatable{ITypeInfo}.Equals(ITypeInfo)"/> to compare <see cref="ITypeInfo"/>s instead.
|
|
||||||
/// </remarks>
|
|
||||||
string FullName { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets <see cref="IPropertyInfo"/>s for all properties of the current type excluding indexers.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Indexers in this context refer to the CLR notion of an indexer (<c>this [string name]</c>
|
|
||||||
/// and does not overlap with the semantics of
|
|
||||||
/// <see cref="Razor.Compilation.TagHelpers.TagHelperAttributeDescriptor.IsIndexer"/>.
|
|
||||||
/// </remarks>
|
|
||||||
IEnumerable<IPropertyInfo> Properties { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the type is public.
|
|
||||||
/// </summary>
|
|
||||||
bool IsPublic { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the type is abstract or an interface.
|
|
||||||
/// </summary>
|
|
||||||
bool IsAbstract { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the type is generic.
|
|
||||||
/// </summary>
|
|
||||||
bool IsGenericType { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the type implements the <param name="interfaceTypeInfo"/> interface.
|
|
||||||
/// </summary>
|
|
||||||
bool ImplementsInterface(ITypeInfo interfaceTypeInfo);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="ITypeInfo[]"/> for the <c>TKey</c> and <c>TValue</c> parameters of
|
|
||||||
/// <see cref="IDictionary{TKey, TValue}"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>
|
|
||||||
/// The <see cref="ITypeInfo"/> of <c>TKey</c> and <c>TValue</c>
|
|
||||||
/// parameters if the type implements <see cref="IDictionary{TKey, TValue}"/>, otherwise <c>null</c>.
|
|
||||||
/// </returns>
|
|
||||||
/// <remarks>
|
|
||||||
/// For open generic types, <see cref="ITypeInfo" /> for generic type parameters is <c>null</c>.
|
|
||||||
/// </remarks>
|
|
||||||
ITypeInfo[] GetGenericDictionaryParameters();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// <see cref="IPropertyInfo"/> adapter for <see cref="PropertyInfo"/> instances.
|
|
||||||
/// </summary>
|
|
||||||
public class RuntimePropertyInfo : IPropertyInfo
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of <see cref="RuntimePropertyInfo"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="propertyInfo">The <see cref="PropertyInfo"/> instance to adapt.</param>
|
|
||||||
public RuntimePropertyInfo(PropertyInfo propertyInfo)
|
|
||||||
{
|
|
||||||
if (propertyInfo == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(propertyInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
Property = propertyInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The <see cref="PropertyInfo"/> instance.
|
|
||||||
/// </summary>
|
|
||||||
public PropertyInfo Property { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public bool HasPublicGetter => Property.GetMethod != null && Property.GetMethod.IsPublic;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public bool HasPublicSetter => Property.SetMethod != null && Property.SetMethod.IsPublic;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public string Name => Property.Name;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public ITypeInfo PropertyType => new RuntimeTypeInfo(Property.PropertyType.GetTypeInfo());
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IEnumerable<TAttribute> GetCustomAttributes<TAttribute>() where TAttribute : Attribute
|
|
||||||
=> Property.GetCustomAttributes<TAttribute>(inherit: false);
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override string ToString() =>
|
|
||||||
Property.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,179 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using Microsoft.AspNet.Razor.TagHelpers;
|
|
||||||
using Microsoft.Extensions.Internal;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// <see cref="ITypeInfo"/> adapter for <see cref="System.Reflection.TypeInfo"/> instances.
|
|
||||||
/// </summary>
|
|
||||||
public class RuntimeTypeInfo : ITypeInfo
|
|
||||||
{
|
|
||||||
private static readonly Regex _fullNameSanitizer = new Regex(
|
|
||||||
@", [A-Za-z\.]+, Version=\d+\.\d+\.\d+\.\d+, Culture=neutral, PublicKeyToken=\w+",
|
|
||||||
RegexOptions.ExplicitCapture,
|
|
||||||
Constants.RegexMatchTimeout);
|
|
||||||
|
|
||||||
private static readonly TypeInfo TagHelperTypeInfo = typeof(ITagHelper).GetTypeInfo();
|
|
||||||
private IEnumerable<IPropertyInfo> _properties;
|
|
||||||
private string _sanitizedFullName;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of <see cref="RuntimeTypeInfo"/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="propertyInfo">The <see cref="System.Reflection.TypeInfo"/> instance to adapt.</param>
|
|
||||||
public RuntimeTypeInfo(TypeInfo typeInfo)
|
|
||||||
{
|
|
||||||
if (typeInfo == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(typeInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeInfo = typeInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The <see cref="System.Reflection.TypeInfo"/> instance.
|
|
||||||
/// </summary>
|
|
||||||
public TypeInfo TypeInfo { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public string Name => TypeInfo.Name;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public string FullName => TypeInfo.FullName;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public bool IsAbstract => TypeInfo.IsAbstract;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public bool IsGenericType => TypeInfo.IsGenericType;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public bool IsPublic => TypeInfo.IsPublic;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IEnumerable<IPropertyInfo> Properties
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_properties == null)
|
|
||||||
{
|
|
||||||
_properties = TypeInfo
|
|
||||||
.AsType()
|
|
||||||
.GetRuntimeProperties()
|
|
||||||
.Where(property => property.GetIndexParameters().Length == 0)
|
|
||||||
.Select(property => new RuntimePropertyInfo(property));
|
|
||||||
}
|
|
||||||
|
|
||||||
return _properties;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public bool ImplementsInterface(ITypeInfo interfaceTypeInfo)
|
|
||||||
{
|
|
||||||
if (interfaceTypeInfo == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(interfaceTypeInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
var runtimeTypeInfo = interfaceTypeInfo as RuntimeTypeInfo;
|
|
||||||
if (runtimeTypeInfo == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentException(
|
|
||||||
Resources.FormatArgumentMustBeAnInstanceOf(typeof(RuntimeTypeInfo).FullName),
|
|
||||||
nameof(interfaceTypeInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
return runtimeTypeInfo.TypeInfo.IsInterface && runtimeTypeInfo.TypeInfo.IsAssignableFrom(TypeInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string SanitizedFullName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_sanitizedFullName == null)
|
|
||||||
{
|
|
||||||
_sanitizedFullName = SanitizeFullName(FullName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _sanitizedFullName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IEnumerable<TAttribute> GetCustomAttributes<TAttribute>() where TAttribute : Attribute =>
|
|
||||||
TypeInfo.GetCustomAttributes<TAttribute>(inherit: false);
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public ITypeInfo[] GetGenericDictionaryParameters()
|
|
||||||
{
|
|
||||||
return ClosedGenericMatcher.ExtractGenericInterface(
|
|
||||||
TypeInfo.AsType(),
|
|
||||||
typeof(IDictionary<,>))
|
|
||||||
?.GenericTypeArguments
|
|
||||||
.Select(type => type.IsGenericParameter ? null : new RuntimeTypeInfo(type.GetTypeInfo()))
|
|
||||||
.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override string ToString() => TypeInfo.ToString();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
return Equals(obj as ITypeInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public bool Equals(ITypeInfo other)
|
|
||||||
{
|
|
||||||
if (other == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var otherRuntimeType = other as RuntimeTypeInfo;
|
|
||||||
if (otherRuntimeType != null)
|
|
||||||
{
|
|
||||||
return otherRuntimeType.TypeInfo == TypeInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Equals(
|
|
||||||
SanitizedFullName,
|
|
||||||
SanitizeFullName(other.FullName),
|
|
||||||
StringComparison.Ordinal);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override int GetHashCode() => SanitizedFullName.GetHashCode();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes assembly qualification from generic type parameters for the specified <paramref name="fullName"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fullName">Full name.</param>
|
|
||||||
/// <returns>Full name without fully qualified generic parameters.</returns>
|
|
||||||
/// <example>
|
|
||||||
/// <c>typeof(<see cref="List{string}"/>).FullName</c> is
|
|
||||||
/// List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]
|
|
||||||
/// <c>Sanitize(typeof(<see cref="List{string}"/>.FullName</c> returns
|
|
||||||
/// List`1[[System.String]
|
|
||||||
/// </example>
|
|
||||||
public static string SanitizeFullName(string fullName)
|
|
||||||
{
|
|
||||||
// In CoreCLR, some types (such as System.String) are type forwarded from System.Runtime
|
|
||||||
// to mscorlib at runtime. Type names of generic type parameters includes the assembly qualified name;
|
|
||||||
// consequently the type name generated at precompilation differs from the one at runtime. We'll
|
|
||||||
// avoid dealing with these inconsistencies by removing assembly information from TypeInfo.FullName.
|
|
||||||
return _fullNameSanitizer.Replace(fullName, string.Empty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,753 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
|
|
||||||
using Microsoft.AspNet.Razor.TagHelpers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Factory for <see cref="TagHelperDescriptor"/>s from <see cref="ITypeInfo"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public static class TagHelperDescriptorFactory
|
|
||||||
{
|
|
||||||
private const string DataDashPrefix = "data-";
|
|
||||||
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,
|
|
||||||
Constants.RegexMatchTimeout);
|
|
||||||
|
|
||||||
private static readonly ITypeInfo StringTypeInfo = new RuntimeTypeInfo(typeof(string).GetTypeInfo());
|
|
||||||
|
|
||||||
// TODO: Investigate if we should cache TagHelperDescriptors for types:
|
|
||||||
// https://github.com/aspnet/Razor/issues/165
|
|
||||||
|
|
||||||
public static ICollection<char> InvalidNonWhitespaceNameCharacters { get; } = new HashSet<char>(
|
|
||||||
new[] { '@', '!', '<', '/', '?', '[', '>', ']', '=', '"', '\'', '*' });
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a <see cref="TagHelperDescriptor"/> from the given <paramref name="typeInfo"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="assemblyName">The assembly name that contains <paramref name="type"/>.</param>
|
|
||||||
/// <param name="typeInfo">The <see cref="ITypeInfo"/> to create a <see cref="TagHelperDescriptor"/> from.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="designTime">Indicates if the returned <see cref="TagHelperDescriptor"/>s should include
|
|
||||||
/// design time specific information.</param>
|
|
||||||
/// <param name="errorSink">The <see cref="ErrorSink"/> used to collect <see cref="RazorError"/>s encountered
|
|
||||||
/// when creating <see cref="TagHelperDescriptor"/>s for the given <paramref name="typeInfo"/>.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// A collection of <see cref="TagHelperDescriptor"/>s that describe the given <paramref name="typeInfo"/>.
|
|
||||||
/// </returns>
|
|
||||||
public static IEnumerable<TagHelperDescriptor> CreateDescriptors(
|
|
||||||
string assemblyName,
|
|
||||||
ITypeInfo typeInfo,
|
|
||||||
bool designTime,
|
|
||||||
ErrorSink errorSink)
|
|
||||||
{
|
|
||||||
if (typeInfo == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(typeInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errorSink == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(errorSink));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ShouldSkipDescriptorCreation(designTime, typeInfo))
|
|
||||||
{
|
|
||||||
return Enumerable.Empty<TagHelperDescriptor>();
|
|
||||||
}
|
|
||||||
|
|
||||||
var attributeDescriptors = GetAttributeDescriptors(typeInfo, designTime, errorSink);
|
|
||||||
var targetElementAttributes = GetValidHtmlTargetElementAttributes(typeInfo, errorSink);
|
|
||||||
var allowedChildren = GetAllowedChildren(typeInfo, errorSink);
|
|
||||||
|
|
||||||
var tagHelperDescriptors =
|
|
||||||
BuildTagHelperDescriptors(
|
|
||||||
typeInfo,
|
|
||||||
assemblyName,
|
|
||||||
attributeDescriptors,
|
|
||||||
targetElementAttributes,
|
|
||||||
allowedChildren,
|
|
||||||
designTime);
|
|
||||||
|
|
||||||
return tagHelperDescriptors.Distinct(TagHelperDescriptorComparer.Default);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<HtmlTargetElementAttribute> GetValidHtmlTargetElementAttributes(
|
|
||||||
ITypeInfo typeInfo,
|
|
||||||
ErrorSink errorSink)
|
|
||||||
{
|
|
||||||
var targetElementAttributes = typeInfo.GetCustomAttributes<HtmlTargetElementAttribute>();
|
|
||||||
|
|
||||||
return targetElementAttributes.Where(
|
|
||||||
attribute => ValidHtmlTargetElementAttributeNames(attribute, errorSink));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<TagHelperDescriptor> BuildTagHelperDescriptors(
|
|
||||||
ITypeInfo typeInfo,
|
|
||||||
string assemblyName,
|
|
||||||
IEnumerable<TagHelperAttributeDescriptor> attributeDescriptors,
|
|
||||||
IEnumerable<HtmlTargetElementAttribute> targetElementAttributes,
|
|
||||||
IEnumerable<string> allowedChildren,
|
|
||||||
bool designTime)
|
|
||||||
{
|
|
||||||
TagHelperDesignTimeDescriptor typeDesignTimeDescriptor = null;
|
|
||||||
|
|
||||||
#if !DOTNET5_4
|
|
||||||
if (designTime)
|
|
||||||
{
|
|
||||||
var runtimeTypeInfo = typeInfo as RuntimeTypeInfo;
|
|
||||||
if (runtimeTypeInfo != null)
|
|
||||||
{
|
|
||||||
typeDesignTimeDescriptor =
|
|
||||||
TagHelperDesignTimeDescriptorFactory.CreateDescriptor(runtimeTypeInfo.TypeInfo.AsType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
var typeName = typeInfo.FullName;
|
|
||||||
|
|
||||||
// If there isn't an attribute specifying the tag name derive it from the name
|
|
||||||
if (!targetElementAttributes.Any())
|
|
||||||
{
|
|
||||||
var name = typeInfo.Name;
|
|
||||||
|
|
||||||
if (name.EndsWith(TagHelperNameEnding, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
name = name.Substring(0, name.Length - TagHelperNameEnding.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new[]
|
|
||||||
{
|
|
||||||
BuildTagHelperDescriptor(
|
|
||||||
ToHtmlCase(name),
|
|
||||||
typeName,
|
|
||||||
assemblyName,
|
|
||||||
attributeDescriptors,
|
|
||||||
requiredAttributes: Enumerable.Empty<string>(),
|
|
||||||
allowedChildren: allowedChildren,
|
|
||||||
tagStructure: default(TagStructure),
|
|
||||||
parentTag: null,
|
|
||||||
designTimeDescriptor: typeDesignTimeDescriptor)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return targetElementAttributes.Select(
|
|
||||||
attribute =>
|
|
||||||
BuildTagHelperDescriptor(
|
|
||||||
typeName,
|
|
||||||
assemblyName,
|
|
||||||
attributeDescriptors,
|
|
||||||
attribute,
|
|
||||||
allowedChildren,
|
|
||||||
typeDesignTimeDescriptor));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<string> GetAllowedChildren(ITypeInfo typeInfo, ErrorSink errorSink)
|
|
||||||
{
|
|
||||||
var restrictChildrenAttribute = typeInfo
|
|
||||||
.GetCustomAttributes<RestrictChildrenAttribute>()
|
|
||||||
.FirstOrDefault();
|
|
||||||
if (restrictChildrenAttribute == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var allowedChildren = restrictChildrenAttribute.ChildTags;
|
|
||||||
var validAllowedChildren = GetValidAllowedChildren(allowedChildren, typeInfo.FullName, errorSink);
|
|
||||||
|
|
||||||
if (validAllowedChildren.Any())
|
|
||||||
{
|
|
||||||
return validAllowedChildren;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// All allowed children were invalid, return null to indicate that any child is acceptable.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal for unit testing
|
|
||||||
internal static IEnumerable<string> GetValidAllowedChildren(
|
|
||||||
IEnumerable<string> allowedChildren,
|
|
||||||
string tagHelperName,
|
|
||||||
ErrorSink errorSink)
|
|
||||||
{
|
|
||||||
var validAllowedChildren = new List<string>();
|
|
||||||
|
|
||||||
foreach (var name in allowedChildren)
|
|
||||||
{
|
|
||||||
var valid = TryValidateName(
|
|
||||||
name,
|
|
||||||
whitespaceError:
|
|
||||||
Resources.FormatTagHelperDescriptorFactory_InvalidRestrictChildrenAttributeNameNullWhitespace(
|
|
||||||
nameof(RestrictChildrenAttribute),
|
|
||||||
tagHelperName),
|
|
||||||
characterErrorBuilder: (invalidCharacter) =>
|
|
||||||
Resources.FormatTagHelperDescriptorFactory_InvalidRestrictChildrenAttributeName(
|
|
||||||
nameof(RestrictChildrenAttribute),
|
|
||||||
name,
|
|
||||||
tagHelperName,
|
|
||||||
invalidCharacter),
|
|
||||||
errorSink: errorSink);
|
|
||||||
|
|
||||||
if (valid)
|
|
||||||
{
|
|
||||||
validAllowedChildren.Add(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return validAllowedChildren;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TagHelperDescriptor BuildTagHelperDescriptor(
|
|
||||||
string typeName,
|
|
||||||
string assemblyName,
|
|
||||||
IEnumerable<TagHelperAttributeDescriptor> attributeDescriptors,
|
|
||||||
HtmlTargetElementAttribute targetElementAttribute,
|
|
||||||
IEnumerable<string> allowedChildren,
|
|
||||||
TagHelperDesignTimeDescriptor designTimeDescriptor)
|
|
||||||
{
|
|
||||||
var requiredAttributes = GetCommaSeparatedValues(targetElementAttribute.Attributes);
|
|
||||||
|
|
||||||
return BuildTagHelperDescriptor(
|
|
||||||
targetElementAttribute.Tag,
|
|
||||||
typeName,
|
|
||||||
assemblyName,
|
|
||||||
attributeDescriptors,
|
|
||||||
requiredAttributes,
|
|
||||||
allowedChildren,
|
|
||||||
targetElementAttribute.ParentTag,
|
|
||||||
targetElementAttribute.TagStructure,
|
|
||||||
designTimeDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TagHelperDescriptor BuildTagHelperDescriptor(
|
|
||||||
string tagName,
|
|
||||||
string typeName,
|
|
||||||
string assemblyName,
|
|
||||||
IEnumerable<TagHelperAttributeDescriptor> attributeDescriptors,
|
|
||||||
IEnumerable<string> requiredAttributes,
|
|
||||||
IEnumerable<string> allowedChildren,
|
|
||||||
string parentTag,
|
|
||||||
TagStructure tagStructure,
|
|
||||||
TagHelperDesignTimeDescriptor designTimeDescriptor)
|
|
||||||
{
|
|
||||||
return new TagHelperDescriptor
|
|
||||||
{
|
|
||||||
TagName = tagName,
|
|
||||||
TypeName = typeName,
|
|
||||||
AssemblyName = assemblyName,
|
|
||||||
Attributes = attributeDescriptors,
|
|
||||||
RequiredAttributes = requiredAttributes,
|
|
||||||
AllowedChildren = allowedChildren,
|
|
||||||
RequiredParent = parentTag,
|
|
||||||
TagStructure = tagStructure,
|
|
||||||
DesignTimeDescriptor = designTimeDescriptor
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Internal for testing.
|
|
||||||
/// </summary>
|
|
||||||
internal static IEnumerable<string> GetCommaSeparatedValues(string text)
|
|
||||||
{
|
|
||||||
// We don't want to remove empty entries, need to notify users of invalid values.
|
|
||||||
return text?.Split(',').Select(tagName => tagName.Trim()) ?? Enumerable.Empty<string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Internal for testing.
|
|
||||||
/// </summary>
|
|
||||||
internal static bool ValidHtmlTargetElementAttributeNames(
|
|
||||||
HtmlTargetElementAttribute attribute,
|
|
||||||
ErrorSink errorSink)
|
|
||||||
{
|
|
||||||
var validTagName = ValidateName(attribute.Tag, targetingAttributes: false, errorSink: errorSink);
|
|
||||||
var validAttributeNames = true;
|
|
||||||
var attributeNames = GetCommaSeparatedValues(attribute.Attributes);
|
|
||||||
|
|
||||||
foreach (var attributeName in attributeNames)
|
|
||||||
{
|
|
||||||
if (!ValidateName(attributeName, targetingAttributes: true, errorSink: errorSink))
|
|
||||||
{
|
|
||||||
validAttributeNames = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var validParentTagName = ValidateParentTagName(attribute.ParentTag, errorSink);
|
|
||||||
|
|
||||||
return validTagName && validAttributeNames && validParentTagName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Internal for unit testing.
|
|
||||||
/// </summary>
|
|
||||||
internal static bool ValidateParentTagName(string parentTag, ErrorSink errorSink)
|
|
||||||
{
|
|
||||||
return parentTag == null ||
|
|
||||||
TryValidateName(
|
|
||||||
parentTag,
|
|
||||||
Resources.FormatHtmlTargetElementAttribute_NameCannotBeNullOrWhitespace(
|
|
||||||
Resources.TagHelperDescriptorFactory_ParentTag),
|
|
||||||
characterErrorBuilder: (invalidCharacter) =>
|
|
||||||
Resources.FormatHtmlTargetElementAttribute_InvalidName(
|
|
||||||
Resources.TagHelperDescriptorFactory_ParentTag.ToLower(),
|
|
||||||
parentTag,
|
|
||||||
invalidCharacter),
|
|
||||||
errorSink: errorSink);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool ValidateName(
|
|
||||||
string name,
|
|
||||||
bool targetingAttributes,
|
|
||||||
ErrorSink errorSink)
|
|
||||||
{
|
|
||||||
if (!targetingAttributes &&
|
|
||||||
string.Equals(
|
|
||||||
name,
|
|
||||||
TagHelperDescriptorProvider.ElementCatchAllTarget,
|
|
||||||
StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
// '*' as the entire name is OK in the HtmlTargetElement catch-all case.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (targetingAttributes &&
|
|
||||||
name.EndsWith(
|
|
||||||
TagHelperDescriptorProvider.RequiredAttributeWildcardSuffix,
|
|
||||||
StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
// A single '*' at the end of a required attribute is valid; everywhere else is invalid. Strip it from
|
|
||||||
// the end so we can validate the rest of the name.
|
|
||||||
name = name.Substring(0, name.Length - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
var targetName = targetingAttributes ?
|
|
||||||
Resources.TagHelperDescriptorFactory_Attribute :
|
|
||||||
Resources.TagHelperDescriptorFactory_Tag;
|
|
||||||
|
|
||||||
var validName = TryValidateName(
|
|
||||||
name,
|
|
||||||
whitespaceError: Resources.FormatHtmlTargetElementAttribute_NameCannotBeNullOrWhitespace(targetName),
|
|
||||||
characterErrorBuilder: (invalidCharacter) =>
|
|
||||||
Resources.FormatHtmlTargetElementAttribute_InvalidName(
|
|
||||||
targetName.ToLower(),
|
|
||||||
name,
|
|
||||||
invalidCharacter),
|
|
||||||
errorSink: errorSink);
|
|
||||||
|
|
||||||
return validName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryValidateName(
|
|
||||||
string name,
|
|
||||||
string whitespaceError,
|
|
||||||
Func<char, string> characterErrorBuilder,
|
|
||||||
ErrorSink errorSink)
|
|
||||||
{
|
|
||||||
var validName = true;
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(name))
|
|
||||||
{
|
|
||||||
errorSink.OnError(SourceLocation.Zero, whitespaceError, length: 0);
|
|
||||||
|
|
||||||
validName = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var character in name)
|
|
||||||
{
|
|
||||||
if (char.IsWhiteSpace(character) ||
|
|
||||||
InvalidNonWhitespaceNameCharacters.Contains(character))
|
|
||||||
{
|
|
||||||
var error = characterErrorBuilder(character);
|
|
||||||
errorSink.OnError(SourceLocation.Zero, error, length: 0);
|
|
||||||
|
|
||||||
validName = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return validName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<TagHelperAttributeDescriptor> GetAttributeDescriptors(
|
|
||||||
ITypeInfo type,
|
|
||||||
bool designTime,
|
|
||||||
ErrorSink errorSink)
|
|
||||||
{
|
|
||||||
var attributeDescriptors = new List<TagHelperAttributeDescriptor>();
|
|
||||||
|
|
||||||
// Keep indexer descriptors separate to avoid sorting the combined list later.
|
|
||||||
var indexerDescriptors = new List<TagHelperAttributeDescriptor>();
|
|
||||||
|
|
||||||
var accessibleProperties = type.Properties.Where(IsAccessibleProperty);
|
|
||||||
foreach (var property in accessibleProperties)
|
|
||||||
{
|
|
||||||
if (ShouldSkipDescriptorCreation(designTime, property))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var attributeNameAttribute = property
|
|
||||||
.GetCustomAttributes<HtmlAttributeNameAttribute>()
|
|
||||||
.FirstOrDefault();
|
|
||||||
var hasExplicitName =
|
|
||||||
attributeNameAttribute != null && !string.IsNullOrEmpty(attributeNameAttribute.Name);
|
|
||||||
var attributeName = hasExplicitName ? attributeNameAttribute.Name : ToHtmlCase(property.Name);
|
|
||||||
|
|
||||||
TagHelperAttributeDescriptor mainDescriptor = null;
|
|
||||||
if (property.HasPublicSetter)
|
|
||||||
{
|
|
||||||
mainDescriptor = ToAttributeDescriptor(property, attributeName, designTime);
|
|
||||||
if (!ValidateTagHelperAttributeDescriptor(mainDescriptor, type, errorSink))
|
|
||||||
{
|
|
||||||
// HtmlAttributeNameAttribute.Name is invalid. Ignore this property completely.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (hasExplicitName)
|
|
||||||
{
|
|
||||||
// Specified HtmlAttributeNameAttribute.Name though property has no public setter.
|
|
||||||
errorSink.OnError(
|
|
||||||
SourceLocation.Zero,
|
|
||||||
Resources.FormatTagHelperDescriptorFactory_InvalidAttributeNameNotNullOrEmpty(
|
|
||||||
type.FullName,
|
|
||||||
property.Name,
|
|
||||||
typeof(HtmlAttributeNameAttribute).FullName,
|
|
||||||
nameof(HtmlAttributeNameAttribute.Name)),
|
|
||||||
length: 0);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isInvalid;
|
|
||||||
var indexerDescriptor = ToIndexerAttributeDescriptor(
|
|
||||||
property,
|
|
||||||
attributeNameAttribute,
|
|
||||||
parentType: type,
|
|
||||||
errorSink: errorSink,
|
|
||||||
defaultPrefix: attributeName + "-",
|
|
||||||
designTime: designTime,
|
|
||||||
isInvalid: out isInvalid);
|
|
||||||
if (indexerDescriptor != null &&
|
|
||||||
!ValidateTagHelperAttributeDescriptor(indexerDescriptor, type, errorSink))
|
|
||||||
{
|
|
||||||
isInvalid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isInvalid)
|
|
||||||
{
|
|
||||||
// The property type or HtmlAttributeNameAttribute.DictionaryAttributePrefix (or perhaps the
|
|
||||||
// HTML-casing of the property name) is invalid. Ignore this property completely.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mainDescriptor != null)
|
|
||||||
{
|
|
||||||
attributeDescriptors.Add(mainDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (indexerDescriptor != null)
|
|
||||||
{
|
|
||||||
indexerDescriptors.Add(indexerDescriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
attributeDescriptors.AddRange(indexerDescriptors);
|
|
||||||
|
|
||||||
return attributeDescriptors;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal for testing.
|
|
||||||
internal static bool ValidateTagHelperAttributeDescriptor(
|
|
||||||
TagHelperAttributeDescriptor attributeDescriptor,
|
|
||||||
ITypeInfo parentType,
|
|
||||||
ErrorSink errorSink)
|
|
||||||
{
|
|
||||||
string nameOrPrefix;
|
|
||||||
if (attributeDescriptor.IsIndexer)
|
|
||||||
{
|
|
||||||
nameOrPrefix = Resources.TagHelperDescriptorFactory_Prefix;
|
|
||||||
}
|
|
||||||
else if (string.IsNullOrEmpty(attributeDescriptor.Name))
|
|
||||||
{
|
|
||||||
errorSink.OnError(
|
|
||||||
SourceLocation.Zero,
|
|
||||||
Resources.FormatTagHelperDescriptorFactory_InvalidAttributeNameNullOrEmpty(
|
|
||||||
parentType.FullName,
|
|
||||||
attributeDescriptor.PropertyName),
|
|
||||||
length: 0);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nameOrPrefix = Resources.TagHelperDescriptorFactory_Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ValidateTagHelperAttributeNameOrPrefix(
|
|
||||||
attributeDescriptor.Name,
|
|
||||||
parentType,
|
|
||||||
attributeDescriptor.PropertyName,
|
|
||||||
errorSink,
|
|
||||||
nameOrPrefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool ShouldSkipDescriptorCreation(bool designTime, IMemberInfo memberInfo)
|
|
||||||
{
|
|
||||||
if (designTime)
|
|
||||||
{
|
|
||||||
var editorBrowsableAttribute = memberInfo
|
|
||||||
.GetCustomAttributes<EditorBrowsableAttribute>()
|
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
return editorBrowsableAttribute != null &&
|
|
||||||
editorBrowsableAttribute.State == EditorBrowsableState.Never;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool ValidateTagHelperAttributeNameOrPrefix(
|
|
||||||
string attributeNameOrPrefix,
|
|
||||||
ITypeInfo parentType,
|
|
||||||
string propertyName,
|
|
||||||
ErrorSink errorSink,
|
|
||||||
string nameOrPrefix)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(attributeNameOrPrefix))
|
|
||||||
{
|
|
||||||
// ValidateTagHelperAttributeDescriptor validates Name is non-null and non-empty. The empty string is
|
|
||||||
// valid for DictionaryAttributePrefix and null is impossible at this point because it means "don't
|
|
||||||
// create a descriptor". (Empty DictionaryAttributePrefix is a corner case which would bind every
|
|
||||||
// attribute of a target element. Likely not particularly useful but unclear what minimum length
|
|
||||||
// should be required and what scenarios a minimum length would break.)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(attributeNameOrPrefix))
|
|
||||||
{
|
|
||||||
// Provide a single error if the entire name is whitespace, not an error per character.
|
|
||||||
errorSink.OnError(
|
|
||||||
SourceLocation.Zero,
|
|
||||||
Resources.FormatTagHelperDescriptorFactory_InvalidAttributeNameOrPrefixWhitespace(
|
|
||||||
parentType.FullName,
|
|
||||||
propertyName,
|
|
||||||
nameOrPrefix),
|
|
||||||
length: 0);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// data-* attributes are explicitly not implemented by user agents and are not intended for use on
|
|
||||||
// the server; therefore it's invalid for TagHelpers to bind to them.
|
|
||||||
if (attributeNameOrPrefix.StartsWith(DataDashPrefix, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
errorSink.OnError(
|
|
||||||
SourceLocation.Zero,
|
|
||||||
Resources.FormatTagHelperDescriptorFactory_InvalidAttributeNameOrPrefixStart(
|
|
||||||
parentType.FullName,
|
|
||||||
propertyName,
|
|
||||||
nameOrPrefix,
|
|
||||||
attributeNameOrPrefix,
|
|
||||||
DataDashPrefix),
|
|
||||||
length: 0);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var isValid = true;
|
|
||||||
foreach (var character in attributeNameOrPrefix)
|
|
||||||
{
|
|
||||||
if (char.IsWhiteSpace(character) || InvalidNonWhitespaceNameCharacters.Contains(character))
|
|
||||||
{
|
|
||||||
errorSink.OnError(
|
|
||||||
SourceLocation.Zero,
|
|
||||||
Resources.FormatTagHelperDescriptorFactory_InvalidAttributeNameOrPrefixCharacter(
|
|
||||||
parentType.FullName,
|
|
||||||
propertyName,
|
|
||||||
nameOrPrefix,
|
|
||||||
attributeNameOrPrefix,
|
|
||||||
character),
|
|
||||||
length: 0);
|
|
||||||
|
|
||||||
isValid = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return isValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TagHelperAttributeDescriptor ToAttributeDescriptor(
|
|
||||||
IPropertyInfo property,
|
|
||||||
string attributeName,
|
|
||||||
bool designTime)
|
|
||||||
{
|
|
||||||
return ToAttributeDescriptor(
|
|
||||||
property,
|
|
||||||
attributeName,
|
|
||||||
property.PropertyType.FullName,
|
|
||||||
isIndexer: false,
|
|
||||||
isStringProperty: StringTypeInfo.Equals(property.PropertyType),
|
|
||||||
designTime: designTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TagHelperAttributeDescriptor ToIndexerAttributeDescriptor(
|
|
||||||
IPropertyInfo property,
|
|
||||||
HtmlAttributeNameAttribute attributeNameAttribute,
|
|
||||||
ITypeInfo parentType,
|
|
||||||
ErrorSink errorSink,
|
|
||||||
string defaultPrefix,
|
|
||||||
bool designTime,
|
|
||||||
out bool isInvalid)
|
|
||||||
{
|
|
||||||
isInvalid = false;
|
|
||||||
var hasPublicSetter = property.HasPublicSetter;
|
|
||||||
var dictionaryTypeArguments = property.PropertyType.GetGenericDictionaryParameters();
|
|
||||||
if (!StringTypeInfo.Equals(dictionaryTypeArguments?[0]))
|
|
||||||
{
|
|
||||||
if (attributeNameAttribute?.DictionaryAttributePrefix != null)
|
|
||||||
{
|
|
||||||
// DictionaryAttributePrefix is not supported unless associated with an
|
|
||||||
// IDictionary<string, TValue> property.
|
|
||||||
isInvalid = true;
|
|
||||||
errorSink.OnError(
|
|
||||||
SourceLocation.Zero,
|
|
||||||
Resources.FormatTagHelperDescriptorFactory_InvalidAttributePrefixNotNull(
|
|
||||||
parentType.FullName,
|
|
||||||
property.Name,
|
|
||||||
nameof(HtmlAttributeNameAttribute),
|
|
||||||
nameof(HtmlAttributeNameAttribute.DictionaryAttributePrefix),
|
|
||||||
"IDictionary<string, TValue>"),
|
|
||||||
length: 0);
|
|
||||||
}
|
|
||||||
else if (attributeNameAttribute != null && !hasPublicSetter)
|
|
||||||
{
|
|
||||||
// Associated an HtmlAttributeNameAttribute with a non-dictionary property that lacks a public
|
|
||||||
// setter.
|
|
||||||
isInvalid = true;
|
|
||||||
errorSink.OnError(
|
|
||||||
SourceLocation.Zero,
|
|
||||||
Resources.FormatTagHelperDescriptorFactory_InvalidAttributeNameAttribute(
|
|
||||||
parentType.FullName,
|
|
||||||
property.Name,
|
|
||||||
nameof(HtmlAttributeNameAttribute),
|
|
||||||
"IDictionary<string, TValue>"),
|
|
||||||
length: 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else if (!hasPublicSetter &&
|
|
||||||
attributeNameAttribute != null &&
|
|
||||||
!attributeNameAttribute.DictionaryAttributePrefixSet)
|
|
||||||
{
|
|
||||||
// Must set DictionaryAttributePrefix when using HtmlAttributeNameAttribute with a dictionary property
|
|
||||||
// that lacks a public setter.
|
|
||||||
isInvalid = true;
|
|
||||||
errorSink.OnError(
|
|
||||||
SourceLocation.Zero,
|
|
||||||
Resources.FormatTagHelperDescriptorFactory_InvalidAttributePrefixNull(
|
|
||||||
parentType.FullName,
|
|
||||||
property.Name,
|
|
||||||
nameof(HtmlAttributeNameAttribute),
|
|
||||||
nameof(HtmlAttributeNameAttribute.DictionaryAttributePrefix),
|
|
||||||
"IDictionary<string, TValue>"),
|
|
||||||
length: 0);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Potential prefix case. Use default prefix (based on name)?
|
|
||||||
var useDefault = attributeNameAttribute == null || !attributeNameAttribute.DictionaryAttributePrefixSet;
|
|
||||||
|
|
||||||
var prefix = useDefault ? defaultPrefix : attributeNameAttribute.DictionaryAttributePrefix;
|
|
||||||
if (prefix == null)
|
|
||||||
{
|
|
||||||
// DictionaryAttributePrefix explicitly set to null. Ignore.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ToAttributeDescriptor(
|
|
||||||
property,
|
|
||||||
attributeName: prefix,
|
|
||||||
typeName: dictionaryTypeArguments[1].FullName,
|
|
||||||
isIndexer: true,
|
|
||||||
isStringProperty: StringTypeInfo.Equals(dictionaryTypeArguments[1]),
|
|
||||||
designTime: designTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TagHelperAttributeDescriptor ToAttributeDescriptor(
|
|
||||||
IPropertyInfo property,
|
|
||||||
string attributeName,
|
|
||||||
string typeName,
|
|
||||||
bool isIndexer,
|
|
||||||
bool isStringProperty,
|
|
||||||
bool designTime)
|
|
||||||
{
|
|
||||||
TagHelperAttributeDesignTimeDescriptor propertyDesignTimeDescriptor = null;
|
|
||||||
|
|
||||||
#if !DOTNET5_4
|
|
||||||
if (designTime)
|
|
||||||
{
|
|
||||||
var runtimeProperty = property as RuntimePropertyInfo;
|
|
||||||
if (runtimeProperty != null)
|
|
||||||
{
|
|
||||||
propertyDesignTimeDescriptor =
|
|
||||||
TagHelperDesignTimeDescriptorFactory.CreateAttributeDescriptor(runtimeProperty.Property);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return new TagHelperAttributeDescriptor
|
|
||||||
{
|
|
||||||
Name = attributeName,
|
|
||||||
PropertyName = property.Name,
|
|
||||||
TypeName = typeName,
|
|
||||||
IsStringProperty = isStringProperty,
|
|
||||||
IsIndexer = isIndexer,
|
|
||||||
DesignTimeDescriptor = propertyDesignTimeDescriptor
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsAccessibleProperty(IPropertyInfo property)
|
|
||||||
{
|
|
||||||
// Accessible properties are those with public getters and without [HtmlAttributeNotBound].
|
|
||||||
return property.HasPublicGetter &&
|
|
||||||
property.GetCustomAttributes<HtmlAttributeNotBoundAttribute>().FirstOrDefault() == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,307 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
|
|
||||||
using Microsoft.AspNet.Razor.Parser;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Used to resolve <see cref="TagHelperDescriptor"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public class TagHelperDescriptorResolver : ITagHelperDescriptorResolver
|
|
||||||
{
|
|
||||||
private static readonly IReadOnlyDictionary<TagHelperDirectiveType, string> _directiveNames =
|
|
||||||
new Dictionary<TagHelperDirectiveType, string>
|
|
||||||
{
|
|
||||||
{ TagHelperDirectiveType.AddTagHelper, SyntaxConstants.CSharp.AddTagHelperKeyword },
|
|
||||||
{ TagHelperDirectiveType.RemoveTagHelper, SyntaxConstants.CSharp.RemoveTagHelperKeyword },
|
|
||||||
{ TagHelperDirectiveType.TagHelperPrefix, SyntaxConstants.CSharp.TagHelperPrefixKeyword },
|
|
||||||
};
|
|
||||||
|
|
||||||
private readonly TagHelperTypeResolver _typeResolver;
|
|
||||||
private readonly bool _designTime;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of the <see cref="TagHelperDescriptorResolver"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="designTime">Indicates whether resolved <see cref="TagHelperDescriptor"/>s should include
|
|
||||||
/// design time specific information.</param>
|
|
||||||
public TagHelperDescriptorResolver(bool designTime)
|
|
||||||
: this(new TagHelperTypeResolver(), designTime)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of <see cref="TagHelperDescriptorResolver"/> class with the
|
|
||||||
/// specified <paramref name="typeResolver"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="typeResolver">The <see cref="TagHelperTypeResolver"/>.</param>
|
|
||||||
/// <param name="designTime">Indicates whether resolved <see cref="TagHelperDescriptor"/>s should include
|
|
||||||
/// design time specific information.</param>
|
|
||||||
public TagHelperDescriptorResolver(TagHelperTypeResolver typeResolver, bool designTime)
|
|
||||||
{
|
|
||||||
_typeResolver = typeResolver;
|
|
||||||
_designTime = designTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IEnumerable<TagHelperDescriptor> Resolve(TagHelperDescriptorResolutionContext context)
|
|
||||||
{
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
var resolvedDescriptors = new HashSet<TagHelperDescriptor>(TagHelperDescriptorComparer.Default);
|
|
||||||
|
|
||||||
// tagHelperPrefix directives do not affect which TagHelperDescriptors are added or removed from the final
|
|
||||||
// list, need to remove them.
|
|
||||||
var actionableDirectiveDescriptors = context.DirectiveDescriptors.Where(
|
|
||||||
directive => directive.DirectiveType != TagHelperDirectiveType.TagHelperPrefix);
|
|
||||||
|
|
||||||
foreach (var directiveDescriptor in actionableDirectiveDescriptors)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var lookupInfo = GetLookupInfo(directiveDescriptor, context.ErrorSink);
|
|
||||||
|
|
||||||
// Could not resolve the lookup info.
|
|
||||||
if (lookupInfo == null)
|
|
||||||
{
|
|
||||||
return Enumerable.Empty<TagHelperDescriptor>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (directiveDescriptor.DirectiveType == TagHelperDirectiveType.RemoveTagHelper)
|
|
||||||
{
|
|
||||||
resolvedDescriptors.RemoveWhere(descriptor => MatchesLookupInfo(descriptor, lookupInfo));
|
|
||||||
}
|
|
||||||
else if (directiveDescriptor.DirectiveType == TagHelperDirectiveType.AddTagHelper)
|
|
||||||
{
|
|
||||||
var descriptors = ResolveDescriptorsInAssembly(
|
|
||||||
lookupInfo.AssemblyName,
|
|
||||||
lookupInfo.AssemblyNameLocation,
|
|
||||||
context.ErrorSink);
|
|
||||||
|
|
||||||
// Only use descriptors that match our lookup info
|
|
||||||
descriptors = descriptors.Where(descriptor => MatchesLookupInfo(descriptor, lookupInfo));
|
|
||||||
|
|
||||||
resolvedDescriptors.UnionWith(descriptors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
string directiveName;
|
|
||||||
_directiveNames.TryGetValue(directiveDescriptor.DirectiveType, out directiveName);
|
|
||||||
Debug.Assert(!string.IsNullOrEmpty(directiveName));
|
|
||||||
|
|
||||||
context.ErrorSink.OnError(
|
|
||||||
directiveDescriptor.Location,
|
|
||||||
Resources.FormatTagHelperDescriptorResolver_EncounteredUnexpectedError(
|
|
||||||
"@" + directiveName,
|
|
||||||
directiveDescriptor.DirectiveText,
|
|
||||||
ex.Message),
|
|
||||||
GetErrorLength(directiveDescriptor.DirectiveText));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var prefixedDescriptors = PrefixDescriptors(context, resolvedDescriptors);
|
|
||||||
|
|
||||||
return prefixedDescriptors;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Resolves all <see cref="TagHelperDescriptor"/>s for <see cref="Razor.TagHelpers.ITagHelper"/>s from the
|
|
||||||
/// given <paramref name="assemblyName"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="assemblyName">
|
|
||||||
/// The name of the assembly to resolve <see cref="TagHelperDescriptor"/>s from.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="documentLocation">The <see cref="SourceLocation"/> of the directive.</param>
|
|
||||||
/// <param name="errorSink">Used to record errors found when resolving <see cref="TagHelperDescriptor"/>s
|
|
||||||
/// within the given <paramref name="assemblyName"/>.</param>
|
|
||||||
/// <returns><see cref="TagHelperDescriptor"/>s for <see cref="Razor.TagHelpers.ITagHelper"/>s from the given
|
|
||||||
/// <paramref name="assemblyName"/>.</returns>
|
|
||||||
// This is meant to be overridden by tooling to enable assembly level caching.
|
|
||||||
protected virtual IEnumerable<TagHelperDescriptor> ResolveDescriptorsInAssembly(
|
|
||||||
string assemblyName,
|
|
||||||
SourceLocation documentLocation,
|
|
||||||
ErrorSink errorSink)
|
|
||||||
{
|
|
||||||
// Resolve valid tag helper types from the assembly.
|
|
||||||
var tagHelperTypes = _typeResolver.Resolve(assemblyName, documentLocation, errorSink);
|
|
||||||
|
|
||||||
// Convert types to TagHelperDescriptors
|
|
||||||
var descriptors = tagHelperTypes.SelectMany(
|
|
||||||
type => TagHelperDescriptorFactory.CreateDescriptors(assemblyName, type, _designTime, errorSink));
|
|
||||||
|
|
||||||
return descriptors;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<TagHelperDescriptor> PrefixDescriptors(
|
|
||||||
TagHelperDescriptorResolutionContext context,
|
|
||||||
IEnumerable<TagHelperDescriptor> descriptors)
|
|
||||||
{
|
|
||||||
var tagHelperPrefix = ResolveTagHelperPrefix(context);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(tagHelperPrefix))
|
|
||||||
{
|
|
||||||
return descriptors.Select(descriptor =>
|
|
||||||
new TagHelperDescriptor
|
|
||||||
{
|
|
||||||
Prefix = tagHelperPrefix,
|
|
||||||
TagName = descriptor.TagName,
|
|
||||||
TypeName = descriptor.TypeName,
|
|
||||||
AssemblyName = descriptor.AssemblyName,
|
|
||||||
Attributes = descriptor.Attributes,
|
|
||||||
RequiredAttributes = descriptor.RequiredAttributes,
|
|
||||||
AllowedChildren = descriptor.AllowedChildren,
|
|
||||||
RequiredParent = descriptor.RequiredParent,
|
|
||||||
TagStructure = descriptor.TagStructure,
|
|
||||||
DesignTimeDescriptor = descriptor.DesignTimeDescriptor
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return descriptors;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ResolveTagHelperPrefix(TagHelperDescriptorResolutionContext context)
|
|
||||||
{
|
|
||||||
var prefixDirectiveDescriptors = context.DirectiveDescriptors.Where(
|
|
||||||
descriptor => descriptor.DirectiveType == TagHelperDirectiveType.TagHelperPrefix);
|
|
||||||
|
|
||||||
TagHelperDirectiveDescriptor prefixDirective = null;
|
|
||||||
|
|
||||||
foreach (var directive in prefixDirectiveDescriptors)
|
|
||||||
{
|
|
||||||
if (prefixDirective == null)
|
|
||||||
{
|
|
||||||
prefixDirective = directive;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// For each invalid @tagHelperPrefix we need to create an error.
|
|
||||||
context.ErrorSink.OnError(
|
|
||||||
directive.Location,
|
|
||||||
Resources.FormatTagHelperDescriptorResolver_InvalidTagHelperDirective(
|
|
||||||
SyntaxConstants.CSharp.TagHelperPrefixKeyword),
|
|
||||||
GetErrorLength(directive.DirectiveText));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var prefix = prefixDirective?.DirectiveText;
|
|
||||||
|
|
||||||
if (prefix != null && !EnsureValidPrefix(prefix, prefixDirective.Location, context.ErrorSink))
|
|
||||||
{
|
|
||||||
prefix = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return prefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool EnsureValidPrefix(
|
|
||||||
string prefix,
|
|
||||||
SourceLocation directiveLocation,
|
|
||||||
ErrorSink errorSink)
|
|
||||||
{
|
|
||||||
foreach (var character in prefix)
|
|
||||||
{
|
|
||||||
// Prefixes are correlated with tag names, tag names cannot have whitespace.
|
|
||||||
if (char.IsWhiteSpace(character) ||
|
|
||||||
TagHelperDescriptorFactory.InvalidNonWhitespaceNameCharacters.Contains(character))
|
|
||||||
{
|
|
||||||
errorSink.OnError(
|
|
||||||
directiveLocation,
|
|
||||||
Resources.FormatTagHelperDescriptorResolver_InvalidTagHelperPrefixValue(
|
|
||||||
SyntaxConstants.CSharp.TagHelperPrefixKeyword,
|
|
||||||
character,
|
|
||||||
prefix),
|
|
||||||
prefix.Length);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool MatchesLookupInfo(TagHelperDescriptor descriptor, LookupInfo lookupInfo)
|
|
||||||
{
|
|
||||||
if (!string.Equals(descriptor.AssemblyName, lookupInfo.AssemblyName, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lookupInfo.TypePattern.EndsWith("*", StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
if (lookupInfo.TypePattern.Length == 1)
|
|
||||||
{
|
|
||||||
// TypePattern is "*".
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var lookupTypeName = lookupInfo.TypePattern.Substring(0, lookupInfo.TypePattern.Length - 1);
|
|
||||||
|
|
||||||
return descriptor.TypeName.StartsWith(lookupTypeName, StringComparison.Ordinal);
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Equals(descriptor.TypeName, lookupInfo.TypePattern, StringComparison.Ordinal);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static LookupInfo GetLookupInfo(
|
|
||||||
TagHelperDirectiveDescriptor directiveDescriptor,
|
|
||||||
ErrorSink errorSink)
|
|
||||||
{
|
|
||||||
var lookupText = directiveDescriptor.DirectiveText;
|
|
||||||
var lookupStrings = lookupText?.Split(new[] { ',' });
|
|
||||||
|
|
||||||
// Ensure that we have valid lookupStrings to work with. The valid format is "typeName, assemblyName"
|
|
||||||
if (lookupStrings == null ||
|
|
||||||
lookupStrings.Any(string.IsNullOrWhiteSpace) ||
|
|
||||||
lookupStrings.Length != 2)
|
|
||||||
{
|
|
||||||
errorSink.OnError(
|
|
||||||
directiveDescriptor.Location,
|
|
||||||
Resources.FormatTagHelperDescriptorResolver_InvalidTagHelperLookupText(lookupText),
|
|
||||||
GetErrorLength(lookupText));
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var trimmedAssemblyName = lookupStrings[1].Trim();
|
|
||||||
|
|
||||||
// + 1 is for the comma separator in the lookup text.
|
|
||||||
var assemblyNameIndex = lookupStrings[0].Length + 1 + lookupStrings[1].IndexOf(trimmedAssemblyName);
|
|
||||||
var assemblyNamePrefix = directiveDescriptor.DirectiveText.Substring(0, assemblyNameIndex);
|
|
||||||
var assemblyNameLocation = SourceLocation.Advance(directiveDescriptor.Location, assemblyNamePrefix);
|
|
||||||
|
|
||||||
return new LookupInfo
|
|
||||||
{
|
|
||||||
TypePattern = lookupStrings[0].Trim(),
|
|
||||||
AssemblyName = trimmedAssemblyName,
|
|
||||||
AssemblyNameLocation = assemblyNameLocation,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int GetErrorLength(string directiveText)
|
|
||||||
{
|
|
||||||
var nonNullLength = directiveText == null ? 1 : directiveText.Length;
|
|
||||||
var normalizeEmptyStringLength = Math.Max(nonNullLength, 1);
|
|
||||||
|
|
||||||
return normalizeEmptyStringLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class LookupInfo
|
|
||||||
{
|
|
||||||
public string AssemblyName { get; set; }
|
|
||||||
|
|
||||||
public string TypePattern { get; set; }
|
|
||||||
|
|
||||||
public SourceLocation AssemblyNameLocation { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,215 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
#if !DOTNET5_4 // Cannot accurately resolve the location of the documentation XML file in coreclr.
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
|
|
||||||
using Microsoft.AspNet.Razor.TagHelpers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Factory for providing <see cref="TagHelperDesignTimeDescriptor"/>s from <see cref="Type"/>s and
|
|
||||||
/// <see cref="TagHelperAttributeDesignTimeDescriptor"/>s from <see cref="PropertyInfo"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public static class TagHelperDesignTimeDescriptorFactory
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a <see cref="TagHelperDesignTimeDescriptor"/> from the given <paramref name="type"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">
|
|
||||||
/// The <see cref="Type"/> to create a <see cref="TagHelperDesignTimeDescriptor"/> from.
|
|
||||||
/// </param>
|
|
||||||
/// <returns>A <see cref="TagHelperDesignTimeDescriptor"/> that describes design time specific information
|
|
||||||
/// for the given <paramref name="type"/>.</returns>
|
|
||||||
public static TagHelperDesignTimeDescriptor CreateDescriptor(Type type)
|
|
||||||
{
|
|
||||||
if (type == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
var id = XmlDocumentationProvider.GetId(type);
|
|
||||||
var documentationDescriptor = CreateDocumentationDescriptor(type.Assembly, id);
|
|
||||||
|
|
||||||
// Purposefully not using the TypeInfo.GetCustomAttributes method here to make it easier to mock the Type.
|
|
||||||
var outputElementHintAttribute = type
|
|
||||||
.GetCustomAttributes(inherit: false)
|
|
||||||
?.OfType<OutputElementHintAttribute>()
|
|
||||||
.FirstOrDefault();
|
|
||||||
var outputElementHint = outputElementHintAttribute?.OutputElement;
|
|
||||||
|
|
||||||
if (documentationDescriptor != null || outputElementHint != null)
|
|
||||||
{
|
|
||||||
return new TagHelperDesignTimeDescriptor
|
|
||||||
{
|
|
||||||
Summary = documentationDescriptor?.Summary,
|
|
||||||
Remarks = documentationDescriptor?.Remarks,
|
|
||||||
OutputElementHint = outputElementHint
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a <see cref="TagHelperAttributeDesignTimeDescriptor"/> from the given
|
|
||||||
/// <paramref name="propertyInfo"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="propertyInfo">
|
|
||||||
/// The <see cref="PropertyInfo"/> to create a <see cref="TagHelperAttributeDesignTimeDescriptor"/> from.
|
|
||||||
/// </param>
|
|
||||||
/// <returns>A <see cref="TagHelperAttributeDesignTimeDescriptor"/> that describes design time specific
|
|
||||||
/// information for the given <paramref name="propertyInfo"/>.</returns>
|
|
||||||
public static TagHelperAttributeDesignTimeDescriptor CreateAttributeDescriptor(
|
|
||||||
PropertyInfo propertyInfo)
|
|
||||||
{
|
|
||||||
if (propertyInfo == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(propertyInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
var id = XmlDocumentationProvider.GetId(propertyInfo);
|
|
||||||
var declaringAssembly = propertyInfo.DeclaringType.Assembly;
|
|
||||||
var documentationDescriptor = CreateDocumentationDescriptor(declaringAssembly, id);
|
|
||||||
|
|
||||||
if (documentationDescriptor != null)
|
|
||||||
{
|
|
||||||
return new TagHelperAttributeDesignTimeDescriptor
|
|
||||||
{
|
|
||||||
Summary = documentationDescriptor.Summary,
|
|
||||||
Remarks = documentationDescriptor.Remarks
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static DocumentationDescriptor CreateDocumentationDescriptor(Assembly assembly, string id)
|
|
||||||
{
|
|
||||||
var assemblyLocation = assembly.Location;
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(assemblyLocation) && !string.IsNullOrEmpty(assembly.CodeBase))
|
|
||||||
{
|
|
||||||
var uri = new UriBuilder(assembly.CodeBase);
|
|
||||||
|
|
||||||
// Normalize the path to a UNC path. This will remove things like file:// from start of the uri.Path.
|
|
||||||
assemblyLocation = Uri.UnescapeDataString(uri.Path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Couldn't resolve a valid assemblyLocation.
|
|
||||||
if (string.IsNullOrEmpty(assemblyLocation))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var xmlDocumentationFile = GetXmlDocumentationFile(assembly, assemblyLocation);
|
|
||||||
|
|
||||||
// Only want to process the file if it exists.
|
|
||||||
if (xmlDocumentationFile != null)
|
|
||||||
{
|
|
||||||
var documentationProvider = new XmlDocumentationProvider(xmlDocumentationFile.FullName);
|
|
||||||
|
|
||||||
var summary = documentationProvider.GetSummary(id);
|
|
||||||
var remarks = documentationProvider.GetRemarks(id);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(summary) || !string.IsNullOrEmpty(remarks))
|
|
||||||
{
|
|
||||||
return new DocumentationDescriptor
|
|
||||||
{
|
|
||||||
Summary = summary,
|
|
||||||
Remarks = remarks
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static FileInfo GetXmlDocumentationFile(Assembly assembly, string assemblyLocation)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var assemblyDirectory = Path.GetDirectoryName(assemblyLocation);
|
|
||||||
var assemblyName = Path.GetFileName(assemblyLocation);
|
|
||||||
var assemblyXmlDocumentationName = Path.ChangeExtension(assemblyName, ".xml");
|
|
||||||
|
|
||||||
// Check for a localized XML file for the current culture.
|
|
||||||
var xmlDocumentationFile = GetLocalizedXmlDocumentationFile(
|
|
||||||
CultureInfo.CurrentCulture,
|
|
||||||
assemblyDirectory,
|
|
||||||
assemblyXmlDocumentationName);
|
|
||||||
|
|
||||||
if (xmlDocumentationFile == null)
|
|
||||||
{
|
|
||||||
// Check for a culture-neutral XML file next to the assembly
|
|
||||||
xmlDocumentationFile = new FileInfo(
|
|
||||||
Path.Combine(assemblyDirectory, assemblyXmlDocumentationName));
|
|
||||||
|
|
||||||
if (!xmlDocumentationFile.Exists)
|
|
||||||
{
|
|
||||||
xmlDocumentationFile = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return xmlDocumentationFile;
|
|
||||||
}
|
|
||||||
catch (ArgumentException)
|
|
||||||
{
|
|
||||||
// Could not resolve XML file.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<string> ExpandPaths(
|
|
||||||
CultureInfo culture,
|
|
||||||
string assemblyDirectory,
|
|
||||||
string assemblyXmlDocumentationName)
|
|
||||||
{
|
|
||||||
// Following the fall-back process defined by:
|
|
||||||
// https://msdn.microsoft.com/en-us/library/sb6a8618.aspx#cpconpackagingdeployingresourcesanchor1
|
|
||||||
do
|
|
||||||
{
|
|
||||||
var cultureName = culture.Name;
|
|
||||||
var cultureSpecificFileName =
|
|
||||||
Path.ChangeExtension(assemblyXmlDocumentationName, cultureName + ".xml");
|
|
||||||
|
|
||||||
// Look for a culture specific XML file next to the assembly.
|
|
||||||
yield return Path.Combine(assemblyDirectory, cultureSpecificFileName);
|
|
||||||
|
|
||||||
// Look for an XML file with the same name as the assembly in a culture specific directory.
|
|
||||||
yield return Path.Combine(assemblyDirectory, cultureName, assemblyXmlDocumentationName);
|
|
||||||
|
|
||||||
// Look for a culture specific XML file in a culture specific directory.
|
|
||||||
yield return Path.Combine(assemblyDirectory, cultureName, cultureSpecificFileName);
|
|
||||||
|
|
||||||
culture = culture.Parent;
|
|
||||||
} while (culture != null && culture != CultureInfo.InvariantCulture);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static FileInfo GetLocalizedXmlDocumentationFile(
|
|
||||||
CultureInfo culture,
|
|
||||||
string assemblyDirectory,
|
|
||||||
string assemblyXmlDocumentationName)
|
|
||||||
{
|
|
||||||
var localizedXmlPaths = ExpandPaths(culture, assemblyDirectory, assemblyXmlDocumentationName);
|
|
||||||
var xmlDocumentationFile = localizedXmlPaths
|
|
||||||
.Select(path => new FileInfo(path))
|
|
||||||
.FirstOrDefault(file => file.Exists);
|
|
||||||
|
|
||||||
return xmlDocumentationFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DocumentationDescriptor
|
|
||||||
{
|
|
||||||
public string Summary { get; set; }
|
|
||||||
public string Remarks { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,255 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNet.Razor.TagHelpers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Class used to store information about a <see cref="ITagHelper"/>'s execution lifetime.
|
|
||||||
/// </summary>
|
|
||||||
public class TagHelperExecutionContext
|
|
||||||
{
|
|
||||||
private readonly List<ITagHelper> _tagHelpers;
|
|
||||||
private readonly Func<Task> _executeChildContentAsync;
|
|
||||||
private readonly Action _startTagHelperWritingScope;
|
|
||||||
private readonly Func<TagHelperContent> _endTagHelperWritingScope;
|
|
||||||
private TagHelperContent _childContent;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Internal for testing purposes only.
|
|
||||||
/// </summary>
|
|
||||||
internal TagHelperExecutionContext(string tagName, TagMode tagMode)
|
|
||||||
: this(tagName,
|
|
||||||
tagMode,
|
|
||||||
items: new Dictionary<object, object>(),
|
|
||||||
uniqueId: string.Empty,
|
|
||||||
executeChildContentAsync: async () => await Task.FromResult(result: true),
|
|
||||||
startTagHelperWritingScope: () => { },
|
|
||||||
endTagHelperWritingScope: () => new DefaultTagHelperContent())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new <see cref="TagHelperExecutionContext"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tagName">The HTML tag name in the Razor source.</param>
|
|
||||||
/// <param name="tagMode">HTML syntax of the element in the Razor source.</param>
|
|
||||||
/// <param name="items">The collection of items used to communicate with other
|
|
||||||
/// <see cref="ITagHelper"/>s</param>
|
|
||||||
/// <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="startTagHelperWritingScope">A delegate used to start a writing scope in a Razor page.</param>
|
|
||||||
/// <param name="endTagHelperWritingScope">A delegate used to end a writing scope in a Razor page.</param>
|
|
||||||
public TagHelperExecutionContext(
|
|
||||||
string tagName,
|
|
||||||
TagMode tagMode,
|
|
||||||
IDictionary<object, object> items,
|
|
||||||
string uniqueId,
|
|
||||||
Func<Task> executeChildContentAsync,
|
|
||||||
Action startTagHelperWritingScope,
|
|
||||||
Func<TagHelperContent> endTagHelperWritingScope)
|
|
||||||
{
|
|
||||||
if (tagName == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(tagName));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (items == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(items));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uniqueId == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(uniqueId));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (executeChildContentAsync == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(executeChildContentAsync));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startTagHelperWritingScope == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(startTagHelperWritingScope));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endTagHelperWritingScope == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(endTagHelperWritingScope));
|
|
||||||
}
|
|
||||||
|
|
||||||
_tagHelpers = new List<ITagHelper>();
|
|
||||||
_executeChildContentAsync = executeChildContentAsync;
|
|
||||||
_startTagHelperWritingScope = startTagHelperWritingScope;
|
|
||||||
_endTagHelperWritingScope = endTagHelperWritingScope;
|
|
||||||
|
|
||||||
TagMode = tagMode;
|
|
||||||
HTMLAttributes = new TagHelperAttributeList();
|
|
||||||
AllAttributes = new TagHelperAttributeList();
|
|
||||||
TagName = tagName;
|
|
||||||
Items = items;
|
|
||||||
UniqueId = uniqueId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the HTML syntax of the element in the Razor source.
|
|
||||||
/// </summary>
|
|
||||||
public TagMode TagMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates if <see cref="GetChildContentAsync"/> has been called.
|
|
||||||
/// </summary>
|
|
||||||
public bool ChildContentRetrieved
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _childContent != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the collection of items used to communicate with other <see cref="ITagHelper"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public IDictionary<object, object> Items { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// HTML attributes.
|
|
||||||
/// </summary>
|
|
||||||
public TagHelperAttributeList HTMLAttributes { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <see cref="ITagHelper"/> bound attributes and HTML attributes.
|
|
||||||
/// </summary>
|
|
||||||
public TagHelperAttributeList 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.
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<ITagHelper> TagHelpers
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _tagHelpers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The HTML tag name in the Razor source.
|
|
||||||
/// </summary>
|
|
||||||
public string TagName { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The <see cref="ITagHelper"/>s' output.
|
|
||||||
/// </summary>
|
|
||||||
public TagHelperOutput Output { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tracks the given <paramref name="tagHelper"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tagHelper">The tag helper to track.</param>
|
|
||||||
public void Add(ITagHelper tagHelper)
|
|
||||||
{
|
|
||||||
if (tagHelper == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(tagHelper));
|
|
||||||
}
|
|
||||||
|
|
||||||
_tagHelpers.Add(tagHelper);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tracks the minimized HTML attribute in <see cref="AllAttributes"/> and <see cref="HTMLAttributes"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The minimized HTML attribute name.</param>
|
|
||||||
public void AddMinimizedHtmlAttribute(string name)
|
|
||||||
{
|
|
||||||
if (name == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
HTMLAttributes.Add(
|
|
||||||
new TagHelperAttribute
|
|
||||||
{
|
|
||||||
Name = name,
|
|
||||||
Minimized = true
|
|
||||||
});
|
|
||||||
AllAttributes.Add(
|
|
||||||
new TagHelperAttribute
|
|
||||||
{
|
|
||||||
Name = name,
|
|
||||||
Minimized = true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tracks the HTML attribute in <see cref="AllAttributes"/> and <see cref="HTMLAttributes"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The HTML attribute name.</param>
|
|
||||||
/// <param name="value">The HTML attribute value.</param>
|
|
||||||
public void AddHtmlAttribute(string name, object value)
|
|
||||||
{
|
|
||||||
if (name == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
HTMLAttributes.Add(name, value);
|
|
||||||
AllAttributes.Add(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tracks the <see cref="ITagHelper"/> bound attribute in <see cref="AllAttributes"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The bound attribute name.</param>
|
|
||||||
/// <param name="value">The attribute value.</param>
|
|
||||||
public void AddTagHelperAttribute(string name, object value)
|
|
||||||
{
|
|
||||||
if (name == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
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{TagHelperContent}"/> return a cached result.
|
|
||||||
/// </remarks>
|
|
||||||
public async Task<TagHelperContent> GetChildContentAsync(bool useCachedResult)
|
|
||||||
{
|
|
||||||
if (!useCachedResult || _childContent == null)
|
|
||||||
{
|
|
||||||
_startTagHelperWritingScope();
|
|
||||||
await _executeChildContentAsync();
|
|
||||||
_childContent = _endTagHelperWritingScope();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DefaultTagHelperContent().SetContent(_childContent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNet.Razor.TagHelpers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A class used to run <see cref="ITagHelper"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public class TagHelperRunner
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Calls the <see cref="ITagHelper.ProcessAsync"/> method on <see cref="ITagHelper"/>s.
|
|
||||||
/// </summary>
|
|
||||||
/// <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="executionContext"/>'s <see cref="ITagHelper"/>s.</returns>
|
|
||||||
public async Task<TagHelperOutput> RunAsync(TagHelperExecutionContext executionContext)
|
|
||||||
{
|
|
||||||
if (executionContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(executionContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
var tagHelperContext = new TagHelperContext(
|
|
||||||
executionContext.AllAttributes,
|
|
||||||
executionContext.Items,
|
|
||||||
executionContext.UniqueId);
|
|
||||||
var orderedTagHelpers = executionContext.TagHelpers.OrderBy(tagHelper => tagHelper.Order);
|
|
||||||
|
|
||||||
foreach (var tagHelper in orderedTagHelpers)
|
|
||||||
{
|
|
||||||
tagHelper.Init(tagHelperContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
var tagHelperOutput = new TagHelperOutput(
|
|
||||||
executionContext.TagName,
|
|
||||||
executionContext.HTMLAttributes,
|
|
||||||
executionContext.GetChildContentAsync)
|
|
||||||
{
|
|
||||||
TagMode = executionContext.TagMode,
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var tagHelper in orderedTagHelpers)
|
|
||||||
{
|
|
||||||
await tagHelper.ProcessAsync(tagHelperContext, tagHelperOutput);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tagHelperOutput;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,124 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNet.Razor.TagHelpers;
|
|
||||||
using Microsoft.Extensions.Internal;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Class that manages <see cref="TagHelperExecutionContext"/> scopes.
|
|
||||||
/// </summary>
|
|
||||||
public class TagHelperScopeManager
|
|
||||||
{
|
|
||||||
private readonly Stack<TagHelperExecutionContext> _executionScopes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new <see cref="TagHelperScopeManager"/>.
|
|
||||||
/// </summary>
|
|
||||||
public TagHelperScopeManager()
|
|
||||||
{
|
|
||||||
_executionScopes = new Stack<TagHelperExecutionContext>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Starts a <see cref="TagHelperExecutionContext"/> scope.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tagName">The HTML tag name that the scope is associated with.</param>
|
|
||||||
/// <param name="tagMode">HTML syntax of the element in the Razor source.</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="startTagHelperWritingScope">A delegate used to start a writing scope in a Razor page.</param>
|
|
||||||
/// <param name="endTagHelperWritingScope">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,
|
|
||||||
TagMode tagMode,
|
|
||||||
string uniqueId,
|
|
||||||
Func<Task> executeChildContentAsync,
|
|
||||||
Action startTagHelperWritingScope,
|
|
||||||
Func<TagHelperContent> endTagHelperWritingScope)
|
|
||||||
{
|
|
||||||
if (tagName == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(tagName));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uniqueId == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(uniqueId));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (executeChildContentAsync == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(executeChildContentAsync));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startTagHelperWritingScope == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(startTagHelperWritingScope));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endTagHelperWritingScope == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(endTagHelperWritingScope));
|
|
||||||
}
|
|
||||||
|
|
||||||
IDictionary<object, object> items;
|
|
||||||
|
|
||||||
// If we're not wrapped by another TagHelper, then there will not be a parentExecutionContext.
|
|
||||||
if (_executionScopes.Count > 0)
|
|
||||||
{
|
|
||||||
items = new CopyOnWriteDictionary<object, object>(
|
|
||||||
_executionScopes.Peek().Items,
|
|
||||||
comparer: EqualityComparer<object>.Default);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
items = new Dictionary<object, object>();
|
|
||||||
}
|
|
||||||
|
|
||||||
var executionContext = new TagHelperExecutionContext(
|
|
||||||
tagName,
|
|
||||||
tagMode,
|
|
||||||
items,
|
|
||||||
uniqueId,
|
|
||||||
executeChildContentAsync,
|
|
||||||
startTagHelperWritingScope,
|
|
||||||
endTagHelperWritingScope);
|
|
||||||
|
|
||||||
_executionScopes.Push(executionContext);
|
|
||||||
|
|
||||||
return executionContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ends a <see cref="TagHelperExecutionContext"/> scope.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>If the current scope is nested, the parent <see cref="TagHelperExecutionContext"/>.
|
|
||||||
/// <c>null</c> otherwise.</returns>
|
|
||||||
public TagHelperExecutionContext End()
|
|
||||||
{
|
|
||||||
if (_executionScopes.Count == 0)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(
|
|
||||||
Resources.FormatScopeManager_EndCannotBeCalledWithoutACallToBegin(
|
|
||||||
nameof(End),
|
|
||||||
nameof(Begin),
|
|
||||||
nameof(TagHelperScopeManager)));
|
|
||||||
}
|
|
||||||
|
|
||||||
_executionScopes.Pop();
|
|
||||||
|
|
||||||
if (_executionScopes.Count != 0)
|
|
||||||
{
|
|
||||||
return _executionScopes.Peek();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using Microsoft.AspNet.Razor.TagHelpers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Class that locates valid <see cref="ITagHelper"/>s within an assembly.
|
|
||||||
/// </summary>
|
|
||||||
public class TagHelperTypeResolver
|
|
||||||
{
|
|
||||||
private static readonly ITypeInfo ITagHelperTypeInfo = new RuntimeTypeInfo(typeof(ITagHelper).GetTypeInfo());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Locates valid <see cref="ITagHelper"/> types from the <see cref="Assembly"/> named <paramref name="name"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The name of an <see cref="Assembly"/> to search.</param>
|
|
||||||
/// <param name="documentLocation">The <see cref="SourceLocation"/> of the associated
|
|
||||||
/// <see cref="Parser.SyntaxTree.SyntaxTreeNode"/> responsible for the current <see cref="Resolve"/> call.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="errorSink">The <see cref="ErrorSink"/> used to record errors found when resolving
|
|
||||||
/// <see cref="ITagHelper"/> types.</param>
|
|
||||||
/// <returns>An <see cref="IEnumerable{ITypeInfo}"/> of valid <see cref="ITagHelper"/> types.</returns>
|
|
||||||
public IEnumerable<ITypeInfo> Resolve(
|
|
||||||
string name,
|
|
||||||
SourceLocation documentLocation,
|
|
||||||
ErrorSink errorSink)
|
|
||||||
{
|
|
||||||
if (errorSink == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(errorSink));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(name))
|
|
||||||
{
|
|
||||||
var errorLength = name == null ? 1 : Math.Max(name.Length, 1);
|
|
||||||
errorSink.OnError(
|
|
||||||
documentLocation,
|
|
||||||
Resources.TagHelperTypeResolver_TagHelperAssemblyNameCannotBeEmptyOrNull,
|
|
||||||
errorLength);
|
|
||||||
|
|
||||||
return Enumerable.Empty<ITypeInfo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
var assemblyName = new AssemblyName(name);
|
|
||||||
|
|
||||||
IEnumerable<ITypeInfo> libraryTypes;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
libraryTypes = GetTopLevelExportedTypes(assemblyName);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
errorSink.OnError(
|
|
||||||
documentLocation,
|
|
||||||
Resources.FormatTagHelperTypeResolver_CannotResolveTagHelperAssembly(
|
|
||||||
assemblyName.Name,
|
|
||||||
ex.Message),
|
|
||||||
name.Length);
|
|
||||||
|
|
||||||
return Enumerable.Empty<ITypeInfo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return libraryTypes.Where(IsTagHelper);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns all non-nested exported types from the given <paramref name="assemblyName"/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="assemblyName">The <see cref="AssemblyName"/> to get <see cref="ITypeInfo"/>s from.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// An <see cref="IEnumerable{ITypeInfo}"/> of types exported from the given <paramref name="assemblyName"/>.
|
|
||||||
/// </returns>
|
|
||||||
protected virtual IEnumerable<ITypeInfo> GetTopLevelExportedTypes(AssemblyName assemblyName)
|
|
||||||
{
|
|
||||||
if (assemblyName == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(assemblyName));
|
|
||||||
}
|
|
||||||
|
|
||||||
var exportedTypeInfos = GetExportedTypes(assemblyName);
|
|
||||||
|
|
||||||
return exportedTypeInfos
|
|
||||||
.Where(typeInfo => !typeInfo.IsNested)
|
|
||||||
.Select(typeInfo => new RuntimeTypeInfo(typeInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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);
|
|
||||||
|
|
||||||
return assembly.ExportedTypes.Select(type => type.GetTypeInfo());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal for testing.
|
|
||||||
internal virtual bool IsTagHelper(ITypeInfo typeInfo)
|
|
||||||
{
|
|
||||||
return typeInfo.IsPublic &&
|
|
||||||
!typeInfo.IsAbstract &&
|
|
||||||
!typeInfo.IsGenericType &&
|
|
||||||
typeInfo.ImplementsInterface(ITagHelperTypeInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,129 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
#if !DOTNET5_4
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
using System.Xml.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Extracts summary and remarks XML documentation from an XML documentation file.
|
|
||||||
/// </summary>
|
|
||||||
public class XmlDocumentationProvider
|
|
||||||
{
|
|
||||||
private readonly IEnumerable<XElement> _members;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of the <see cref="XmlDocumentationProvider"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="xmlFileLocation">Path to the XML documentation file to read.</param>
|
|
||||||
public XmlDocumentationProvider(string xmlFileLocation)
|
|
||||||
{
|
|
||||||
// XML file processing is defined by: https://msdn.microsoft.com/en-us/library/fsbx0t7x.aspx
|
|
||||||
var xmlDocumentation = XDocument.Load(xmlFileLocation);
|
|
||||||
var documentationRootMembers = xmlDocumentation.Root.Element("members");
|
|
||||||
_members = documentationRootMembers.Elements("member");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieves the <c><summary></c> documentation for the given <paramref name="id"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The id to lookup.</param>
|
|
||||||
/// <returns><c><summary></c> documentation for the given <paramref name="id"/>.</returns>
|
|
||||||
public string GetSummary(string id)
|
|
||||||
{
|
|
||||||
var associatedMemeber = GetMember(id);
|
|
||||||
var summaryElement = associatedMemeber?.Element("summary");
|
|
||||||
|
|
||||||
if (summaryElement != null)
|
|
||||||
{
|
|
||||||
var summaryValue = GetElementValue(summaryElement);
|
|
||||||
|
|
||||||
return summaryValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieves the <c><remarks></c> documentation for the given <paramref name="id"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The id to lookup.</param>
|
|
||||||
/// <returns><c><remarks></c> documentation for the given <paramref name="id"/>.</returns>
|
|
||||||
public string GetRemarks(string id)
|
|
||||||
{
|
|
||||||
var associatedMemeber = GetMember(id);
|
|
||||||
var remarksElement = associatedMemeber?.Element("remarks");
|
|
||||||
|
|
||||||
if (remarksElement != null)
|
|
||||||
{
|
|
||||||
var remarksValue = GetElementValue(remarksElement);
|
|
||||||
|
|
||||||
return remarksValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the <see cref="string"/> identifier for the given <paramref name="type"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The <see cref="Type"/> to get the identifier for.</param>
|
|
||||||
/// <returns>The <see cref="string"/> identifier for the given <paramref name="type"/>.</returns>
|
|
||||||
public static string GetId(Type type)
|
|
||||||
{
|
|
||||||
if (type == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $"T:{type.FullName}";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the <see cref="string"/> identifier for the given <paramref name="propertyInfo"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="propertyInfo">The <see cref="PropertyInfo"/> to get the identifier for.</param>
|
|
||||||
/// <returns>The <see cref="string"/> identifier for the given <paramref name="propertyInfo"/>.</returns>
|
|
||||||
public static string GetId(PropertyInfo propertyInfo)
|
|
||||||
{
|
|
||||||
if (propertyInfo == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(propertyInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
var declaringTypeInfo = propertyInfo.DeclaringType;
|
|
||||||
return $"P:{declaringTypeInfo.FullName}.{propertyInfo.Name}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private XElement GetMember(string id)
|
|
||||||
{
|
|
||||||
var associatedMemeber = _members
|
|
||||||
.FirstOrDefault(element =>
|
|
||||||
string.Equals(element.Attribute("name").Value, id, StringComparison.Ordinal));
|
|
||||||
|
|
||||||
return associatedMemeber;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetElementValue(XElement element)
|
|
||||||
{
|
|
||||||
var stringBuilder = new StringBuilder();
|
|
||||||
var node = element.FirstNode;
|
|
||||||
|
|
||||||
while (node != null)
|
|
||||||
{
|
|
||||||
stringBuilder.Append(node.ToString(SaveOptions.DisableFormatting));
|
|
||||||
|
|
||||||
node = node.NextNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return stringBuilder.ToString().Trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,231 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using Microsoft.AspNet.Html.Abstractions;
|
|
||||||
using Microsoft.AspNet.Razor.TagHelpers;
|
|
||||||
using Microsoft.Extensions.Internal;
|
|
||||||
using Microsoft.Extensions.WebEncoders;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Default concrete <see cref="TagHelperContent"/>.
|
|
||||||
/// </summary>
|
|
||||||
[DebuggerDisplay("{DebuggerToString(),nq}")]
|
|
||||||
public class DefaultTagHelperContent : TagHelperContent
|
|
||||||
{
|
|
||||||
private BufferedHtmlContent _buffer;
|
|
||||||
|
|
||||||
private BufferedHtmlContent Buffer
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_buffer == null)
|
|
||||||
{
|
|
||||||
_buffer = new BufferedHtmlContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _buffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool IsModified => _buffer != null;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <remarks>Returns <c>true</c> for a cleared <see cref="TagHelperContent"/>.</remarks>
|
|
||||||
public override bool IsWhiteSpace
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_buffer == null)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var writer = new EmptyOrWhiteSpaceWriter())
|
|
||||||
{
|
|
||||||
foreach (var entry in _buffer.Entries)
|
|
||||||
{
|
|
||||||
if (entry == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var stringValue = entry as string;
|
|
||||||
if (stringValue != null)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(stringValue))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
((IHtmlContent)entry).WriteTo(writer, HtmlEncoder.Default);
|
|
||||||
if (!writer.IsWhiteSpace)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool IsEmpty
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_buffer == null)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var writer = new EmptyOrWhiteSpaceWriter())
|
|
||||||
{
|
|
||||||
foreach (var entry in _buffer.Entries)
|
|
||||||
{
|
|
||||||
if (entry == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var stringValue = entry as string;
|
|
||||||
if (stringValue != null)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(stringValue))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
((IHtmlContent)entry).WriteTo(writer, HtmlEncoder.Default);
|
|
||||||
if (!writer.IsEmpty)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override TagHelperContent Append(string unencoded)
|
|
||||||
{
|
|
||||||
Buffer.Append(unencoded);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override TagHelperContent AppendHtml(string encoded)
|
|
||||||
{
|
|
||||||
Buffer.AppendHtml(encoded);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override TagHelperContent Append(IHtmlContent htmlContent)
|
|
||||||
{
|
|
||||||
Buffer.Append(htmlContent);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override TagHelperContent Clear()
|
|
||||||
{
|
|
||||||
Buffer.Clear();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override string GetContent()
|
|
||||||
{
|
|
||||||
return GetContent(HtmlEncoder.Default);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override string GetContent(IHtmlEncoder encoder)
|
|
||||||
{
|
|
||||||
if (_buffer == null)
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var writer = new StringWriter())
|
|
||||||
{
|
|
||||||
WriteTo(writer, encoder);
|
|
||||||
return writer.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void WriteTo(TextWriter writer, IHtmlEncoder encoder)
|
|
||||||
{
|
|
||||||
if (writer == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(writer));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (encoder == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(encoder));
|
|
||||||
}
|
|
||||||
|
|
||||||
Buffer.WriteTo(writer, encoder);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string DebuggerToString()
|
|
||||||
{
|
|
||||||
return GetContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overrides Write(string) to find if the content written is empty/whitespace.
|
|
||||||
private class EmptyOrWhiteSpaceWriter : TextWriter
|
|
||||||
{
|
|
||||||
public override Encoding Encoding
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsEmpty { get; private set; } = true;
|
|
||||||
|
|
||||||
public bool IsWhiteSpace { get; private set; } = true;
|
|
||||||
|
|
||||||
#if DOTNET5_4
|
|
||||||
// This is an abstract method in DNXCore
|
|
||||||
public override void Write(char value)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public override void Write(string value)
|
|
||||||
{
|
|
||||||
if (IsEmpty && !string.IsNullOrEmpty(value))
|
|
||||||
{
|
|
||||||
IsEmpty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsWhiteSpace && !string.IsNullOrWhiteSpace(value))
|
|
||||||
{
|
|
||||||
IsWhiteSpace = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Used to override an <see cref="ITagHelper"/> property's HTML attribute name.
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
|
|
||||||
public sealed class HtmlAttributeNameAttribute : Attribute
|
|
||||||
{
|
|
||||||
private string _dictionaryAttributePrefix;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of the <see cref="HtmlAttributeNameAttribute"/> class with <see cref="Name"/>
|
|
||||||
/// equal to <c>null</c>.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Associated property must not have a public setter and must be compatible with
|
|
||||||
/// <see cref="System.Collections.Generic.IDictionary{TKey, TValue}"/> where <c>TKey</c> is
|
|
||||||
/// <see cref="string"/>.
|
|
||||||
/// </remarks>
|
|
||||||
public HtmlAttributeNameAttribute()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of the <see cref="HtmlAttributeNameAttribute"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">
|
|
||||||
/// HTML attribute name for the associated property. Must be <c>null</c> or empty if associated property does
|
|
||||||
/// not have a public setter and is compatible with
|
|
||||||
/// <see cref="System.Collections.Generic.IDictionary{TKey, TValue}"/> where <c>TKey</c> is
|
|
||||||
/// <see cref="string"/>. Otherwise must not be <c>null</c> or empty.
|
|
||||||
/// </param>
|
|
||||||
public HtmlAttributeNameAttribute(string name)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// HTML attribute name of the associated property.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>
|
|
||||||
/// <c>null</c> or empty if and only if associated property does not have a public setter and is compatible
|
|
||||||
/// with <see cref="System.Collections.Generic.IDictionary{TKey, TValue}"/> where <c>TKey</c> is
|
|
||||||
/// <see cref="string"/>.
|
|
||||||
/// </value>
|
|
||||||
public string Name { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the prefix used to match HTML attribute names. Matching attributes are added to the
|
|
||||||
/// associated property (an <see cref="System.Collections.Generic.IDictionary{TKey, TValue}"/>).
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// If non-<c>null</c> associated property must be compatible with
|
|
||||||
/// <see cref="System.Collections.Generic.IDictionary{TKey, TValue}"/> where <c>TKey</c> is
|
|
||||||
/// <see cref="string"/>.
|
|
||||||
/// </remarks>
|
|
||||||
/// <value>
|
|
||||||
/// <para>
|
|
||||||
/// If associated property is compatible with
|
|
||||||
/// <see cref="System.Collections.Generic.IDictionary{TKey, TValue}"/>, default value is <c>Name + "-"</c>.
|
|
||||||
/// <see cref="Name"/> must not be <c>null</c> or empty in this case.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// Otherwise default value is <c>null</c>.
|
|
||||||
/// </para>
|
|
||||||
/// </value>
|
|
||||||
public string DictionaryAttributePrefix
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _dictionaryAttributePrefix;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_dictionaryAttributePrefix = value;
|
|
||||||
DictionaryAttributePrefixSet = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets an indication whether <see cref="DictionaryAttributePrefix"/> has been set. Used to distinguish an
|
|
||||||
/// uninitialized <see cref="DictionaryAttributePrefix"/> value from an explicit <c>null</c> setting.
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if <see cref="DictionaryAttributePrefix"/> was set. <c>false</c> otherwise.</value>
|
|
||||||
public bool DictionaryAttributePrefixSet { get; private set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates the associated <see cref="ITagHelper"/> property should not be bound to HTML attributes.
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
|
|
||||||
public sealed class HtmlAttributeNotBoundAttribute : Attribute
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of the <see cref="HtmlAttributeNotBoundAttribute"/> class.
|
|
||||||
/// </summary>
|
|
||||||
public HtmlAttributeNotBoundAttribute()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Provides an <see cref="ITagHelper"/>'s target.
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
|
|
||||||
public sealed class HtmlTargetElementAttribute : Attribute
|
|
||||||
{
|
|
||||||
public const string ElementCatchAllTarget = TagHelperDescriptorProvider.ElementCatchAllTarget;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of the <see cref="HtmlTargetElementAttribute"/> class that targets all HTML
|
|
||||||
/// elements with the required <see cref="Attributes"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks><see cref="Tag"/> is set to <c>*</c>.</remarks>
|
|
||||||
public HtmlTargetElementAttribute()
|
|
||||||
: this(ElementCatchAllTarget)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of the <see cref="HtmlTargetElementAttribute"/> class with the given
|
|
||||||
/// <paramref name="tag"/> as its <see cref="Tag"/> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tag">
|
|
||||||
/// The HTML tag the <see cref="ITagHelper"/> targets.
|
|
||||||
/// </param>
|
|
||||||
/// <remarks>A <c>*</c> <paramref name="tag"/> value indicates this <see cref="ITagHelper"/>
|
|
||||||
/// targets all HTML elements with the required <see cref="Attributes"/>.</remarks>
|
|
||||||
public HtmlTargetElementAttribute(string tag)
|
|
||||||
{
|
|
||||||
Tag = tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The HTML tag the <see cref="ITagHelper"/> targets. A <c>*</c> value indicates this <see cref="ITagHelper"/>
|
|
||||||
/// targets all HTML elements with the required <see cref="Attributes"/>.
|
|
||||||
/// </summary>
|
|
||||||
public string Tag { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A comma-separated <see cref="string"/> of attribute names the HTML element must contain for the
|
|
||||||
/// <see cref="ITagHelper"/> to run. <c>*</c> at the end of an attribute name acts as a prefix match.
|
|
||||||
/// </summary>
|
|
||||||
public string Attributes { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The expected tag structure. Defaults to <see cref="TagStructure.Unspecified"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// If <see cref="TagStructure.Unspecified"/> and no other tag helpers applying to the same element specify
|
|
||||||
/// their <see cref="TagStructure"/> the <see cref="TagStructure.NormalOrSelfClosing"/> behavior is used:
|
|
||||||
/// <para>
|
|
||||||
/// <code>
|
|
||||||
/// <my-tag-helper></my-tag-helper>
|
|
||||||
/// <!-- OR -->
|
|
||||||
/// <my-tag-helper />
|
|
||||||
/// </code>
|
|
||||||
/// Otherwise, if another tag helper applying to the same element does specify their behavior, that behavior
|
|
||||||
/// is used.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// If <see cref="TagStructure.WithoutEndTag"/> HTML elements can be written in the following formats:
|
|
||||||
/// <code>
|
|
||||||
/// <my-tag-helper>
|
|
||||||
/// <!-- OR -->
|
|
||||||
/// <my-tag-helper />
|
|
||||||
/// </code>
|
|
||||||
/// </para>
|
|
||||||
/// </remarks>
|
|
||||||
public TagStructure TagStructure { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The required HTML element name of the direct parent. A <c>null</c> value indicates any HTML element name is
|
|
||||||
/// allowed.
|
|
||||||
/// </summary>
|
|
||||||
public string ParentTag { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A read-only HTML tag helper attribute.
|
|
||||||
/// </summary>
|
|
||||||
public interface IReadOnlyTagHelperAttribute : IEquatable<IReadOnlyTagHelperAttribute>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the name of the attribute.
|
|
||||||
/// </summary>
|
|
||||||
string Name { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the value of the attribute.
|
|
||||||
/// </summary>
|
|
||||||
object Value { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets an indication whether the attribute is minimized or not.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>If <c>true</c>, <see cref="Value"/> will be ignored.</remarks>
|
|
||||||
bool Minimized { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Contract used to filter matching HTML elements.
|
|
||||||
/// </summary>
|
|
||||||
public interface ITagHelper
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// When a set of<see cref= "ITagHelper" /> s are executed, their<see cref="Init(TagHelperContext)"/>'s
|
|
||||||
/// are first invoked in the specified <see cref="Order"/>; then their
|
|
||||||
/// <see cref="ProcessAsync(TagHelperContext, TagHelperOutput)"/>'s are invoked in the specified
|
|
||||||
/// <see cref="Order"/>. Lower values are executed first.
|
|
||||||
/// </summary>
|
|
||||||
int Order { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the <see cref="ITagHelper"/> with the given <paramref name="context"/>. Additions to
|
|
||||||
/// <see cref="TagHelperContext.Items"/> should be done within this method to ensure they're added prior to
|
|
||||||
/// executing the children.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">Contains information associated with the current HTML tag.</param>
|
|
||||||
/// <remarks>When more than one <see cref="ITagHelper"/> runs on the same element,
|
|
||||||
/// <see cref="TagHelperOutput.GetChildContentAsync"/> may be invoked prior to <see cref="ProcessAsync"/>.
|
|
||||||
/// </remarks>
|
|
||||||
void Init(TagHelperContext context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Asynchronously executes the <see cref="ITagHelper"/> with the given <paramref name="context"/> and
|
|
||||||
/// <paramref name="output"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">Contains information associated with the current HTML tag.</param>
|
|
||||||
/// <param name="output">A stateful HTML element used to generate an HTML tag.</param>
|
|
||||||
/// <returns>A <see cref="Task"/> that on completion updates the <paramref name="output"/>.</returns>
|
|
||||||
Task ProcessAsync(TagHelperContext context, TagHelperOutput output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Provides a hint of the <see cref="ITagHelper"/>'s output element.
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
|
||||||
public sealed class OutputElementHintAttribute : Attribute
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of the <see cref="OutputElementHintAttribute"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="outputElement">
|
|
||||||
/// The HTML element the <see cref="ITagHelper"/> may output.
|
|
||||||
/// </param>
|
|
||||||
public OutputElementHintAttribute(string outputElement)
|
|
||||||
{
|
|
||||||
if (outputElement == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(outputElement));
|
|
||||||
}
|
|
||||||
|
|
||||||
OutputElement = outputElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The HTML element the <see cref="ITagHelper"/> may output.
|
|
||||||
/// </summary>
|
|
||||||
public string OutputElement { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,235 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.Extensions.Internal;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A read-only collection of <typeparamref name="TAttribute"/>s.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TAttribute">
|
|
||||||
/// The type of <see cref="IReadOnlyTagHelperAttribute"/>s in the collection.
|
|
||||||
/// </typeparam>
|
|
||||||
public class ReadOnlyTagHelperAttributeList<TAttribute> : IReadOnlyList<TAttribute>
|
|
||||||
where TAttribute : IReadOnlyTagHelperAttribute
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of <see cref="ReadOnlyTagHelperAttributeList{TAttribute}"/> with an empty
|
|
||||||
/// collection.
|
|
||||||
/// </summary>
|
|
||||||
protected ReadOnlyTagHelperAttributeList()
|
|
||||||
{
|
|
||||||
Attributes = new List<TAttribute>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of <see cref="ReadOnlyTagHelperAttributeList{TAttribute}"/> with the specified
|
|
||||||
/// <paramref name="attributes"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="attributes">The collection to wrap.</param>
|
|
||||||
public ReadOnlyTagHelperAttributeList(IEnumerable<TAttribute> attributes)
|
|
||||||
{
|
|
||||||
if (attributes == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(attributes));
|
|
||||||
}
|
|
||||||
|
|
||||||
Attributes = new List<TAttribute>(attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The underlying collection of <typeparamref name="TAttribute"/>s.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>Intended for use in a non-read-only subclass. Changes to this <see cref="List{TAttribute}"/> will
|
|
||||||
/// affect all getters that <see cref="ReadOnlyTagHelperAttributeList{TAttribute}"/> provides.</remarks>
|
|
||||||
protected List<TAttribute> Attributes { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public TAttribute this[int index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Attributes[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the first <typeparamref name="TAttribute"/> with <see cref="IReadOnlyTagHelperAttribute.Name"/>
|
|
||||||
/// matching <paramref name="name"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">
|
|
||||||
/// The <see cref="IReadOnlyTagHelperAttribute.Name"/> of the <typeparamref name="TAttribute"/> to get.
|
|
||||||
/// </param>
|
|
||||||
/// <returns>The first <typeparamref name="TAttribute"/> with <see cref="IReadOnlyTagHelperAttribute.Name"/>
|
|
||||||
/// matching <paramref name="name"/>.
|
|
||||||
/// </returns>
|
|
||||||
/// <remarks><paramref name="name"/> is compared case-insensitively.</remarks>
|
|
||||||
public TAttribute this[string name]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (name == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Attributes.FirstOrDefault(attribute => NameEquals(name, attribute));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Attributes.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether a <typeparamref name="TAttribute"/> matching <paramref name="item"/> exists in the
|
|
||||||
/// collection.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">The <typeparamref name="TAttribute"/> to locate.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// <c>true</c> if an <typeparamref name="TAttribute"/> matching <paramref name="item"/> exists in the
|
|
||||||
/// collection; otherwise, <c>false</c>.
|
|
||||||
/// </returns>
|
|
||||||
/// <remarks>
|
|
||||||
/// <paramref name="item"/>s <see cref="IReadOnlyTagHelperAttribute.Name"/> is compared case-insensitively.
|
|
||||||
/// </remarks>
|
|
||||||
public bool Contains(TAttribute item)
|
|
||||||
{
|
|
||||||
if (item == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(item));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Attributes.Contains(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether a <typeparamref name="TAttribute"/> with the same
|
|
||||||
/// <see cref="IReadOnlyTagHelperAttribute.Name"/> exists in the collection.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The <see cref="IReadOnlyTagHelperAttribute.Name"/> of the
|
|
||||||
/// <typeparamref name="TAttribute"/> to get.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// <c>true</c> if a <typeparamref name="TAttribute"/> with the same
|
|
||||||
/// <see cref="IReadOnlyTagHelperAttribute.Name"/> exists in the collection; otherwise, <c>false</c>.
|
|
||||||
/// </returns>
|
|
||||||
/// <remarks><paramref name="name"/> is compared case-insensitively.</remarks>
|
|
||||||
public bool ContainsName(string name)
|
|
||||||
{
|
|
||||||
if (name == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Attributes.Any(attribute => NameEquals(name, attribute));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Searches for a <typeparamref name="TAttribute"/> matching <paramref name="item"/> in the collection and
|
|
||||||
/// returns the zero-based index of the first occurrence.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">The <typeparamref name="TAttribute"/> to locate.</param>
|
|
||||||
/// <returns>The zero-based index of the first occurrence of a <typeparamref name="TAttribute"/> matching
|
|
||||||
/// <paramref name="item"/> in the collection, if found; otherwise, –1.</returns>
|
|
||||||
/// <remarks>
|
|
||||||
/// <paramref name="item"/>s <see cref="IReadOnlyTagHelperAttribute.Name"/> is compared case-insensitively.
|
|
||||||
/// </remarks>
|
|
||||||
public int IndexOf(TAttribute item)
|
|
||||||
{
|
|
||||||
if (item == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(item));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Attributes.IndexOf(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieves the first <typeparamref name="TAttribute"/> with <see cref="IReadOnlyTagHelperAttribute.Name"/>
|
|
||||||
/// matching <paramref name="name"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The <see cref="IReadOnlyTagHelperAttribute.Name"/> of the
|
|
||||||
/// <typeparamref name="TAttribute"/> to get.</param>
|
|
||||||
/// <param name="attribute">When this method returns, the first <typeparamref name="TAttribute"/> with
|
|
||||||
/// <see cref="IReadOnlyTagHelperAttribute.Name"/> matching <paramref name="name"/>, if found; otherwise,
|
|
||||||
/// <c>null</c>.</param>
|
|
||||||
/// <returns><c>true</c> if a <typeparamref name="TAttribute"/> with the same
|
|
||||||
/// <see cref="IReadOnlyTagHelperAttribute.Name"/> exists in the collection; otherwise, <c>false</c>.</returns>
|
|
||||||
/// <remarks><paramref name="name"/> is compared case-insensitively.</remarks>
|
|
||||||
public bool TryGetAttribute(string name, out TAttribute attribute)
|
|
||||||
{
|
|
||||||
if (name == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
attribute = Attributes.FirstOrDefault(attr => NameEquals(name, attr));
|
|
||||||
|
|
||||||
return attribute != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieves <typeparamref name="TAttribute"/>s in the collection with
|
|
||||||
/// <see cref="IReadOnlyTagHelperAttribute.Name"/> matching <paramref name="name"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The <see cref="IReadOnlyTagHelperAttribute.Name"/> of the
|
|
||||||
/// <typeparamref name="TAttribute"/>s to get.</param>
|
|
||||||
/// <param name="attributes">When this method returns, the <typeparamref name="TAttribute"/>s with
|
|
||||||
/// <see cref="IReadOnlyTagHelperAttribute.Name"/> matching <paramref name="name"/>, if at least one is
|
|
||||||
/// found; otherwise, <c>null</c>.</param>
|
|
||||||
/// <returns><c>true</c> if at least one <typeparamref name="TAttribute"/> with the same
|
|
||||||
/// <see cref="IReadOnlyTagHelperAttribute.Name"/> exists in the collection; otherwise, <c>false</c>.</returns>
|
|
||||||
/// <remarks><paramref name="name"/> is compared case-insensitively.</remarks>
|
|
||||||
public bool TryGetAttributes(string name, out IEnumerable<TAttribute> attributes)
|
|
||||||
{
|
|
||||||
if (name == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
attributes = Attributes.Where(attribute => NameEquals(name, attribute));
|
|
||||||
|
|
||||||
return attributes.Any();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IEnumerator<TAttribute> GetEnumerator()
|
|
||||||
{
|
|
||||||
return Attributes.GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines if the specified <paramref name="attribute"/> has the same name as <paramref name="name"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The value to compare against <paramref name="attribute"/>s
|
|
||||||
/// <see cref="TagHelperAttribute.Name"/>.</param>
|
|
||||||
/// <param name="attribute">The attribute to compare against.</param>
|
|
||||||
/// <returns><c>true</c> if <paramref name="name"/> case-insensitively matches <paramref name="attribute"/>s
|
|
||||||
/// <see cref="TagHelperAttribute.Name"/>.</returns>
|
|
||||||
protected static bool NameEquals(string name, TAttribute attribute)
|
|
||||||
{
|
|
||||||
if (attribute == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(attribute));
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Equals(name, attribute.Name, StringComparison.OrdinalIgnoreCase);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Restricts children of the <see cref="ITagHelper"/>'s element.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>Combining this attribute with a <see cref="HtmlTargetElementAttribute"/> that specifies its
|
|
||||||
/// <see cref="HtmlTargetElementAttribute.TagStructure"/> as <see cref="TagStructure.WithoutEndTag"/> will result
|
|
||||||
/// in this attribute being ignored.</remarks>
|
|
||||||
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
|
|
||||||
public class RestrictChildrenAttribute : Attribute
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of the <see cref="RestrictChildrenAttribute"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="childTag">
|
|
||||||
/// The tag name of an element allowed as a child.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="childTags">
|
|
||||||
/// Additional names of elements allowed as children.
|
|
||||||
/// </param>
|
|
||||||
public RestrictChildrenAttribute(string childTag, params string[] childTags)
|
|
||||||
{
|
|
||||||
var concatenatedNames = new string[1 + childTags.Length];
|
|
||||||
concatenatedNames[0] = childTag;
|
|
||||||
|
|
||||||
childTags.CopyTo(concatenatedNames, 1);
|
|
||||||
|
|
||||||
ChildTags = concatenatedNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the names of elements allowed as children.
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<string> ChildTags { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Class used to filter matching HTML elements.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class TagHelper : ITagHelper
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <remarks>Default order is <c>0</c>.</remarks>
|
|
||||||
public virtual int Order { get; } = 0;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual void Init(TagHelperContext context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Synchronously executes the <see cref="TagHelper"/> with the given <paramref name="context"/> and
|
|
||||||
/// <paramref name="output"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">Contains information associated with the current HTML tag.</param>
|
|
||||||
/// <param name="output">A stateful HTML element used to generate an HTML tag.</param>
|
|
||||||
public virtual void Process(TagHelperContext context, TagHelperOutput output)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Asynchronously executes the <see cref="TagHelper"/> with the given <paramref name="context"/> and
|
|
||||||
/// <paramref name="output"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">Contains information associated with the current HTML tag.</param>
|
|
||||||
/// <param name="output">A stateful HTML element used to generate an HTML tag.</param>
|
|
||||||
/// <returns>A <see cref="Task"/> that on completion updates the <paramref name="output"/>.</returns>
|
|
||||||
/// <remarks>By default this calls into <see cref="Process"/>.</remarks>.
|
|
||||||
#pragma warning disable 1998
|
|
||||||
public virtual async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
|
|
||||||
{
|
|
||||||
Process(context, output);
|
|
||||||
}
|
|
||||||
#pragma warning restore 1998
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An HTML tag helper attribute.
|
|
||||||
/// </summary>
|
|
||||||
public class TagHelperAttribute : IReadOnlyTagHelperAttribute
|
|
||||||
{
|
|
||||||
private static readonly int TypeHashCode = typeof(TagHelperAttribute).GetHashCode();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of <see cref="TagHelperAttribute"/>.
|
|
||||||
/// </summary>
|
|
||||||
public TagHelperAttribute()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of <see cref="TagHelperAttribute" /> with values provided by the given
|
|
||||||
/// <paramref name="attribute"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="attribute">A <see cref="IReadOnlyTagHelperAttribute"/> whose values should be copied.</param>
|
|
||||||
public TagHelperAttribute(IReadOnlyTagHelperAttribute attribute)
|
|
||||||
: this(attribute?.Name, attribute?.Value)
|
|
||||||
{
|
|
||||||
if (attribute == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(attribute));
|
|
||||||
}
|
|
||||||
|
|
||||||
Minimized = attribute.Minimized;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of <see cref="TagHelperAttribute"/> with the specified <paramref name="name"/>
|
|
||||||
/// and <paramref name="value"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The <see cref="Name"/> of the attribute.</param>
|
|
||||||
/// <param name="value">The <see cref="Value"/> of the attribute.</param>
|
|
||||||
public TagHelperAttribute(string name, object value)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
Value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the name of the attribute.
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the value of the attribute.
|
|
||||||
/// </summary>
|
|
||||||
public object Value { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets an indication whether the attribute is minimized or not.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>If <c>true</c>, <see cref="Value"/> will be ignored.</remarks>
|
|
||||||
public bool Minimized { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts the specified <paramref name="value"/> into a <see cref="TagHelperAttribute"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The <see cref="Value"/> of the created <see cref="TagHelperAttribute"/>.</param>
|
|
||||||
/// <remarks>Created <see cref="TagHelperAttribute"/>s <see cref="Name"/> is set to <c>null</c>.</remarks>
|
|
||||||
public static implicit operator TagHelperAttribute(string value)
|
|
||||||
{
|
|
||||||
return new TagHelperAttribute
|
|
||||||
{
|
|
||||||
Value = value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <remarks><see cref="Name"/> is compared case-insensitively.</remarks>
|
|
||||||
public bool Equals(IReadOnlyTagHelperAttribute other)
|
|
||||||
{
|
|
||||||
return
|
|
||||||
other != null &&
|
|
||||||
string.Equals(Name, other.Name, StringComparison.OrdinalIgnoreCase) &&
|
|
||||||
Minimized == other.Minimized &&
|
|
||||||
(Minimized || Equals(Value, other.Value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
var other = obj as IReadOnlyTagHelperAttribute;
|
|
||||||
|
|
||||||
return Equals(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return TypeHashCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,292 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Microsoft.AspNet.Razor.Runtime;
|
|
||||||
using Microsoft.Extensions.Internal;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A collection of <see cref="TagHelperAttribute"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public class TagHelperAttributeList : ReadOnlyTagHelperAttributeList<TagHelperAttribute>, IList<TagHelperAttribute>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of <see cref="TagHelperAttributeList"/> with an empty collection.
|
|
||||||
/// </summary>
|
|
||||||
public TagHelperAttributeList()
|
|
||||||
: base()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of <see cref="TagHelperAttributeList"/> with the specified
|
|
||||||
/// <paramref name="attributes"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="attributes">The collection to wrap.</param>
|
|
||||||
public TagHelperAttributeList(IEnumerable<TagHelperAttribute> attributes)
|
|
||||||
: base(attributes)
|
|
||||||
{
|
|
||||||
if (attributes == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(attributes));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <remarks>
|
|
||||||
/// <paramref name="value"/>'s <see cref="TagHelperAttribute.Name"/> must not be <c>null</c>.
|
|
||||||
/// </remarks>
|
|
||||||
public new TagHelperAttribute this[int index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return base[index];
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value.Name == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentException(
|
|
||||||
Resources.FormatTagHelperAttributeList_CannotAddWithNullName(
|
|
||||||
typeof(TagHelperAttribute).FullName,
|
|
||||||
nameof(TagHelperAttribute.Name)),
|
|
||||||
nameof(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Attributes[index] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the first <see cref="TagHelperAttribute"/> with <see cref="TagHelperAttribute.Name"/> matching
|
|
||||||
/// <paramref name="name"/>. When setting, replaces the first matching
|
|
||||||
/// <see cref="TagHelperAttribute"/> with the specified <paramref name="value"/> and removes any additional
|
|
||||||
/// matching <see cref="TagHelperAttribute"/>s. If a matching <see cref="TagHelperAttribute"/> is not found,
|
|
||||||
/// adds the specified <paramref name="value"/> to the end of the collection.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">
|
|
||||||
/// The <see cref="TagHelperAttribute.Name"/> of the <see cref="TagHelperAttribute"/> to get or set.
|
|
||||||
/// </param>
|
|
||||||
/// <returns>The first <see cref="TagHelperAttribute"/> with <see cref="TagHelperAttribute.Name"/> matching
|
|
||||||
/// <paramref name="name"/>.
|
|
||||||
/// </returns>
|
|
||||||
/// <remarks><paramref name="name"/> is compared case-insensitively. When setting,
|
|
||||||
/// <see cref="TagHelperAttribute"/>s <see cref="TagHelperAttribute.Name"/> must be <c>null</c> or
|
|
||||||
/// case-insensitively match the specified <paramref name="name"/>.</remarks>
|
|
||||||
/// <example>
|
|
||||||
/// <code>
|
|
||||||
/// var attributes = new TagHelperAttributeList();
|
|
||||||
///
|
|
||||||
/// // Will "value" be converted to a TagHelperAttribute with a null Name
|
|
||||||
/// attributes["name"] = "value";
|
|
||||||
///
|
|
||||||
/// // TagHelperAttribute.Name must match the specified name.
|
|
||||||
/// attributes["name"] = new TagHelperAttribute("name", "value");
|
|
||||||
/// </code>
|
|
||||||
/// </example>
|
|
||||||
public new TagHelperAttribute this[string name]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (name == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
return base[name];
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (name == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name will be null if user attempts to set the attribute via an implicit conversion:
|
|
||||||
// output.Attributes["someName"] = "someValue"
|
|
||||||
if (value.Name == null)
|
|
||||||
{
|
|
||||||
value.Name = name;
|
|
||||||
}
|
|
||||||
else if (!NameEquals(name, value))
|
|
||||||
{
|
|
||||||
throw new ArgumentException(
|
|
||||||
Resources.FormatTagHelperAttributeList_CannotAddAttribute(
|
|
||||||
nameof(TagHelperAttribute),
|
|
||||||
nameof(TagHelperAttribute.Name),
|
|
||||||
value.Name,
|
|
||||||
name),
|
|
||||||
nameof(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
var attributeReplaced = false;
|
|
||||||
|
|
||||||
for (var i = 0; i < Attributes.Count; i++)
|
|
||||||
{
|
|
||||||
if (NameEquals(name, Attributes[i]))
|
|
||||||
{
|
|
||||||
// We replace the first attribute with the provided value, remove all the rest.
|
|
||||||
if (!attributeReplaced)
|
|
||||||
{
|
|
||||||
// We replace the first attribute we find with the same name.
|
|
||||||
Attributes[i] = value;
|
|
||||||
attributeReplaced = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Attributes.RemoveAt(i--);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we didn't replace an attribute value we should add value to the end of the collection.
|
|
||||||
if (!attributeReplaced)
|
|
||||||
{
|
|
||||||
Add(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
bool ICollection<TagHelperAttribute>.IsReadOnly
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a <see cref="TagHelperAttribute"/> to the end of the collection with the specified
|
|
||||||
/// <paramref name="name"/> and <paramref name="value"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The <see cref="TagHelperAttribute.Name"/> of the attribute to add.</param>
|
|
||||||
/// <param name="value">The <see cref="TagHelperAttribute.Value"/> of the attribute to add.</param>
|
|
||||||
public void Add(string name, object value)
|
|
||||||
{
|
|
||||||
if (name == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
Attributes.Add(new TagHelperAttribute(name, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <remarks>
|
|
||||||
/// <paramref name="attribute"/>'s <see cref="TagHelperAttribute.Name"/> must not be <c>null</c>.
|
|
||||||
/// </remarks>
|
|
||||||
public void Add(TagHelperAttribute attribute)
|
|
||||||
{
|
|
||||||
if (attribute == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(attribute));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attribute.Name == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentException(
|
|
||||||
Resources.FormatTagHelperAttributeList_CannotAddWithNullName(
|
|
||||||
typeof(TagHelperAttribute).FullName,
|
|
||||||
nameof(TagHelperAttribute.Name)),
|
|
||||||
nameof(attribute));
|
|
||||||
}
|
|
||||||
|
|
||||||
Attributes.Add(attribute);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <remarks>
|
|
||||||
/// <paramref name="attribute"/>'s <see cref="TagHelperAttribute.Name"/> must not be <c>null</c>.
|
|
||||||
/// </remarks>
|
|
||||||
public void Insert(int index, TagHelperAttribute attribute)
|
|
||||||
{
|
|
||||||
if (attribute == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(attribute));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attribute.Name == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentException(
|
|
||||||
Resources.FormatTagHelperAttributeList_CannotAddWithNullName(
|
|
||||||
typeof(TagHelperAttribute).FullName,
|
|
||||||
nameof(TagHelperAttribute.Name)),
|
|
||||||
nameof(attribute));
|
|
||||||
}
|
|
||||||
|
|
||||||
Attributes.Insert(index, attribute);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void CopyTo(TagHelperAttribute[] array, int index)
|
|
||||||
{
|
|
||||||
if (array == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(array));
|
|
||||||
}
|
|
||||||
|
|
||||||
Attributes.CopyTo(array, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <remarks>
|
|
||||||
/// <paramref name="attribute"/>s <see cref="TagHelperAttribute.Name"/> is compared case-insensitively.
|
|
||||||
/// </remarks>
|
|
||||||
public bool Remove(TagHelperAttribute attribute)
|
|
||||||
{
|
|
||||||
if (attribute == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(attribute));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Attributes.Remove(attribute);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void RemoveAt(int index)
|
|
||||||
{
|
|
||||||
Attributes.RemoveAt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes all <see cref="TagHelperAttribute"/>s with <see cref="TagHelperAttribute.Name"/> matching
|
|
||||||
/// <paramref name="name"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">
|
|
||||||
/// The <see cref="TagHelperAttribute.Name"/> of <see cref="TagHelperAttribute"/>s to remove.
|
|
||||||
/// </param>
|
|
||||||
/// <returns>
|
|
||||||
/// <c>true</c> if at least 1 <see cref="TagHelperAttribute"/> was removed; otherwise, <c>false</c>.
|
|
||||||
/// </returns>
|
|
||||||
/// <remarks><paramref name="name"/> is compared case-insensitively.</remarks>
|
|
||||||
public bool RemoveAll(string name)
|
|
||||||
{
|
|
||||||
if (name == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Attributes.RemoveAll(attribute => NameEquals(name, attribute)) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
Attributes.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,171 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using Microsoft.AspNet.Html.Abstractions;
|
|
||||||
using Microsoft.Extensions.WebEncoders;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Abstract class used to buffer content returned by <see cref="ITagHelper"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class TagHelperContent : IHtmlContentBuilder
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the content was modifed.
|
|
||||||
/// </summary>
|
|
||||||
public abstract bool IsModified { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the content is empty.
|
|
||||||
/// </summary>
|
|
||||||
public abstract bool IsEmpty { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the content is whitespace.
|
|
||||||
/// </summary>
|
|
||||||
public abstract bool IsWhiteSpace { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the content.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="htmlContent">The <see cref="IHtmlContent"/> that replaces the content.</param>
|
|
||||||
/// <returns>A reference to this instance after the set operation has completed.</returns>
|
|
||||||
public TagHelperContent SetContent(IHtmlContent htmlContent)
|
|
||||||
{
|
|
||||||
HtmlContentBuilderExtensions.SetContent(this, htmlContent);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the content.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="unencoded">
|
|
||||||
/// The <see cref="string"/> that replaces the content. The value is assume to be unencoded
|
|
||||||
/// as-provided and will be HTML encoded before being written.
|
|
||||||
/// </param>
|
|
||||||
/// <returns>A reference to this instance after the set operation has completed.</returns>
|
|
||||||
public TagHelperContent SetContent(string unencoded)
|
|
||||||
{
|
|
||||||
HtmlContentBuilderExtensions.SetContent(this, unencoded);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the content.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encoded">
|
|
||||||
/// The <see cref="string"/> that replaces the content. The value is assume to be HTML encoded
|
|
||||||
/// as-provided and no further encoding will be performed.
|
|
||||||
/// </param>
|
|
||||||
/// <returns>A reference to this instance after the set operation has completed.</returns>
|
|
||||||
public TagHelperContent SetHtmlContent(string encoded)
|
|
||||||
{
|
|
||||||
HtmlContentBuilderExtensions.SetHtmlContent(this, encoded);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Appends <paramref name="unencoded"/> to the existing content.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="unencoded">The <see cref="string"/> to be appended.</param>
|
|
||||||
/// <returns>A reference to this instance after the append operation has completed.</returns>
|
|
||||||
public abstract TagHelperContent Append(string unencoded);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Appends <paramref name="htmlContent"/> to the existing content.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="htmlContent">The <see cref="IHtmlContent"/> to be appended.</param>
|
|
||||||
/// <returns>A reference to this instance after the append operation has completed.</returns>
|
|
||||||
public abstract TagHelperContent Append(IHtmlContent htmlContent);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Appends <paramref name="encoded"/> to the existing content. <paramref name="encoded"/> is assumed
|
|
||||||
/// to be an HTML encoded <see cref="string"/> and no further encoding will be performed.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encoded">The <see cref="string"/> to be appended.</param>
|
|
||||||
/// <returns>A reference to this instance after the append operation has completed.</returns>
|
|
||||||
public abstract TagHelperContent AppendHtml(string encoded);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Appends the specified <paramref name="format"/> to the existing content after
|
|
||||||
/// replacing each format item with the HTML encoded <see cref="string"/> representation of the
|
|
||||||
/// corresponding item in the <paramref name="args"/> array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="format">
|
|
||||||
/// The composite format <see cref="string"/> (see http://msdn.microsoft.com/en-us/library/txafckwd.aspx).
|
|
||||||
/// </param>
|
|
||||||
/// <param name="args">The object array to format.</param>
|
|
||||||
/// <returns>A reference to this instance after the append operation has completed.</returns>
|
|
||||||
public TagHelperContent AppendFormat(string format, params object[] args)
|
|
||||||
{
|
|
||||||
HtmlContentBuilderExtensions.AppendFormat(this, null, format, args);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Appends the specified <paramref name="format"/> to the existing content with information from the
|
|
||||||
/// <paramref name="provider"/> after replacing each format item with the HTML encoded <see cref="string"/>
|
|
||||||
/// representation of the corresponding item in the <paramref name="args"/> array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
|
||||||
/// <param name="format">
|
|
||||||
/// The composite format <see cref="string"/> (see http://msdn.microsoft.com/en-us/library/txafckwd.aspx).
|
|
||||||
/// </param>
|
|
||||||
/// <param name="args">The object array to format.</param>
|
|
||||||
/// <returns>A reference to this instance after the append operation has completed.</returns>
|
|
||||||
public TagHelperContent AppendFormat(IFormatProvider provider, string format, params object[] args)
|
|
||||||
{
|
|
||||||
HtmlContentBuilderExtensions.AppendFormat(this, provider, format, args);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clears the content.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A reference to this instance after the clear operation has completed.</returns>
|
|
||||||
public abstract TagHelperContent Clear();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the content.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A <see cref="string"/> containing the content.</returns>
|
|
||||||
public abstract string GetContent();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the content.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encoder">The <see cref="IHtmlEncoder"/>.</param>
|
|
||||||
/// <returns>A <see cref="string"/> containing the content.</returns>
|
|
||||||
public abstract string GetContent(IHtmlEncoder encoder);
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public abstract void WriteTo(TextWriter writer, IHtmlEncoder encoder);
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
IHtmlContentBuilder IHtmlContentBuilder.Append(IHtmlContent content)
|
|
||||||
{
|
|
||||||
return Append(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
IHtmlContentBuilder IHtmlContentBuilder.Append(string unencoded)
|
|
||||||
{
|
|
||||||
return Append(unencoded);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
IHtmlContentBuilder IHtmlContentBuilder.AppendHtml(string encoded)
|
|
||||||
{
|
|
||||||
return AppendHtml(encoded);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
IHtmlContentBuilder IHtmlContentBuilder.Clear()
|
|
||||||
{
|
|
||||||
return Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Contains information related to the execution of <see cref="ITagHelper"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public class TagHelperContext
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new <see cref="TagHelperContext"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="allAttributes">Every attribute associated with the current HTML element.</param>
|
|
||||||
/// <param name="items">Collection of items used to communicate with other <see cref="ITagHelper"/>s.</param>
|
|
||||||
/// <param name="uniqueId">The unique identifier for the source element this <see cref="TagHelperContext" />
|
|
||||||
/// applies to.</param>
|
|
||||||
public TagHelperContext(
|
|
||||||
IEnumerable<IReadOnlyTagHelperAttribute> allAttributes,
|
|
||||||
IDictionary<object, object> items,
|
|
||||||
string uniqueId)
|
|
||||||
{
|
|
||||||
if (allAttributes == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(allAttributes));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (items == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(items));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uniqueId == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(uniqueId));
|
|
||||||
}
|
|
||||||
|
|
||||||
AllAttributes = new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
|
|
||||||
allAttributes.Select(attribute => new TagHelperAttribute(attribute.Name, attribute.Value)));
|
|
||||||
Items = items;
|
|
||||||
UniqueId = uniqueId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Every attribute associated with the current HTML element.
|
|
||||||
/// </summary>
|
|
||||||
public ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute> AllAttributes { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the collection of items used to communicate with other <see cref="ITagHelper"/>s.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This <see cref="IDictionary{object, object}"/> is copy-on-write in order to ensure items added to this
|
|
||||||
/// collection are visible only to other <see cref="ITagHelper"/>s targeting child elements.
|
|
||||||
/// </remarks>
|
|
||||||
public IDictionary<object, object> Items { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An identifier unique to the HTML element this context is for.
|
|
||||||
/// </summary>
|
|
||||||
public string UniqueId { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,155 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Class used to represent the output of an <see cref="ITagHelper"/>.
|
|
||||||
/// </summary>
|
|
||||||
public class TagHelperOutput
|
|
||||||
{
|
|
||||||
private readonly Func<bool, Task<TagHelperContent>> _getChildContentAsync;
|
|
||||||
|
|
||||||
// Internal for testing
|
|
||||||
internal TagHelperOutput(string tagName)
|
|
||||||
: this(
|
|
||||||
tagName,
|
|
||||||
new TagHelperAttributeList(),
|
|
||||||
(cachedResult) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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="getChildContentAsync">A delegate used to execute and retrieve the rendered child content
|
|
||||||
/// asynchronously.</param>
|
|
||||||
public TagHelperOutput(
|
|
||||||
string tagName,
|
|
||||||
TagHelperAttributeList attributes,
|
|
||||||
Func<bool, Task<TagHelperContent>> getChildContentAsync)
|
|
||||||
{
|
|
||||||
if (attributes == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(attributes));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getChildContentAsync == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(getChildContentAsync));
|
|
||||||
}
|
|
||||||
|
|
||||||
TagName = tagName;
|
|
||||||
Attributes = new TagHelperAttributeList(attributes);
|
|
||||||
_getChildContentAsync = getChildContentAsync;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The HTML element's tag name.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// A whitespace or <c>null</c> value results in no start or end tag being rendered.
|
|
||||||
/// </remarks>
|
|
||||||
public string TagName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Content that precedes the HTML element.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>Value is rendered before the HTML element.</remarks>
|
|
||||||
public TagHelperContent PreElement { get; } = new DefaultTagHelperContent();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The HTML element's pre content.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>Value is prepended to the <see cref="ITagHelper"/>'s final output.</remarks>
|
|
||||||
public TagHelperContent PreContent { get; } = new DefaultTagHelperContent();
|
|
||||||
|
|
||||||
/// <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 TagHelperContent Content { get; } = new DefaultTagHelperContent();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The HTML element's post content.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>Value is appended to the <see cref="ITagHelper"/>'s final output.</remarks>
|
|
||||||
public TagHelperContent PostContent { get; } = new DefaultTagHelperContent();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Content that follows the HTML element.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>Value is rendered after the HTML element.</remarks>
|
|
||||||
public TagHelperContent PostElement { get; } = new DefaultTagHelperContent();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <c>true</c> if <see cref="Content"/> has been set, <c>false</c> otherwise.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsContentModified
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Content.IsModified;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Syntax of the element in the generated HTML.
|
|
||||||
/// </summary>
|
|
||||||
public TagMode TagMode { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The HTML element's attributes.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// MVC will HTML encode <see cref="string"/> values when generating the start tag. It will not HTML encode
|
|
||||||
/// a <c>Microsoft.AspNet.Mvc.Rendering.HtmlString</c> instance. MVC converts most other types to a
|
|
||||||
/// <see cref="string"/>, then HTML encodes the result.
|
|
||||||
/// </remarks>
|
|
||||||
public TagHelperAttributeList Attributes { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Changes <see cref="TagHelperOutput"/> to generate nothing.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Sets <see cref="TagName"/> to <c>null</c>, and clears <see cref="PreElement"/>, <see cref="PreContent"/>,
|
|
||||||
/// <see cref="Content"/>, <see cref="PostContent"/>, and <see cref="PostElement"/> to suppress output.
|
|
||||||
/// </remarks>
|
|
||||||
public void SuppressOutput()
|
|
||||||
{
|
|
||||||
TagName = null;
|
|
||||||
PreElement.Clear();
|
|
||||||
PreContent.Clear();
|
|
||||||
Content.Clear();
|
|
||||||
PostContent.Clear();
|
|
||||||
PostElement.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A delegate used to execute children asynchronously.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A <see cref="Task"/> that on completion returns content rendered by children.</returns>
|
|
||||||
/// <remarks>This method is memoized.</remarks>
|
|
||||||
public Task<TagHelperContent> GetChildContentAsync()
|
|
||||||
{
|
|
||||||
return GetChildContentAsync(useCachedResult: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A delegate used to execute children asynchronously.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="useCachedResult">If <c>true</c> multiple calls to this method will not cause re-execution
|
|
||||||
/// of child content; cached content will be returned.</param>
|
|
||||||
/// <returns>A <see cref="Task"/> that on completion returns content rendered by children.</returns>
|
|
||||||
public Task<TagHelperContent> GetChildContentAsync(bool useCachedResult)
|
|
||||||
{
|
|
||||||
return _getChildContentAsync(useCachedResult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
{
|
|
||||||
"description": "Runtime components for rendering Razor pages.",
|
|
||||||
"version": "4.0.0-rc1-final",
|
|
||||||
"buildOptions": {
|
|
||||||
"warningsAsErrors": true,
|
|
||||||
"keyFile": "../../tools/Key.snk"
|
|
||||||
},
|
|
||||||
"packOptions": {
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git://github.com/aspnet/razor"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"Microsoft.AspNet.Html.Abstractions": "1.0.0-rc1-final",
|
|
||||||
"Microsoft.AspNet.Razor.VSRC1": "4.0.0-rc1-final"
|
|
||||||
},
|
|
||||||
"frameworks": {
|
|
||||||
"net451": {
|
|
||||||
"frameworkAssemblies": {
|
|
||||||
"System.Xml": "4.0.0.0",
|
|
||||||
"System.Xml.Linq": "4.0.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.AspNet.Razor.Chunks.Generators;
|
|
||||||
using Microsoft.AspNet.Razor.CodeGenerators;
|
|
||||||
using Microsoft.AspNet.Razor.Parser;
|
|
||||||
#if NET451
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Defines the C# Code Language for Razor
|
|
||||||
/// </summary>
|
|
||||||
public class CSharpRazorCodeLanguage : RazorCodeLanguage
|
|
||||||
{
|
|
||||||
private const string CSharpLanguageName = "csharp";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the name of the language: "csharp"
|
|
||||||
/// </summary>
|
|
||||||
public override string LanguageName
|
|
||||||
{
|
|
||||||
get { return CSharpLanguageName; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs a new instance of the code parser for this language
|
|
||||||
/// </summary>
|
|
||||||
public override ParserBase CreateCodeParser()
|
|
||||||
{
|
|
||||||
return new CSharpCodeParser();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs a new instance of the chunk generator for this language with the specified settings
|
|
||||||
/// </summary>
|
|
||||||
public override RazorChunkGenerator CreateChunkGenerator(
|
|
||||||
string className,
|
|
||||||
string rootNamespaceName,
|
|
||||||
string sourceFileName,
|
|
||||||
RazorEngineHost host)
|
|
||||||
{
|
|
||||||
return new RazorChunkGenerator(className, rootNamespaceName, sourceFileName, host);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override CodeGenerator CreateCodeGenerator(CodeGeneratorContext context)
|
|
||||||
{
|
|
||||||
return new CSharpCodeGenerator(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A <see cref="Chunk"/> used to look up <see cref="Compilation.TagHelpers.TagHelperDescriptor"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public class AddTagHelperChunk : Chunk
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Text used to look up <see cref="Compilation.TagHelpers.TagHelperDescriptor"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public string LookupText { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
public class Chunk
|
|
||||||
{
|
|
||||||
public SourceLocation Start { get; set; }
|
|
||||||
public SyntaxTreeNode Association { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
public class ChunkTree
|
|
||||||
{
|
|
||||||
public ChunkTree()
|
|
||||||
{
|
|
||||||
Chunks = new List<Chunk>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IList<Chunk> Chunks { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,169 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
public class ChunkTreeBuilder
|
|
||||||
{
|
|
||||||
private readonly Stack<ParentChunk> _parentStack;
|
|
||||||
private Chunk _lastChunk;
|
|
||||||
|
|
||||||
public ChunkTreeBuilder()
|
|
||||||
{
|
|
||||||
ChunkTree = new ChunkTree();
|
|
||||||
_parentStack = new Stack<ParentChunk>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChunkTree ChunkTree { get; private set; }
|
|
||||||
|
|
||||||
public void AddChunk(Chunk chunk, SyntaxTreeNode association, bool topLevel = false)
|
|
||||||
{
|
|
||||||
_lastChunk = chunk;
|
|
||||||
|
|
||||||
chunk.Start = association.Start;
|
|
||||||
chunk.Association = association;
|
|
||||||
|
|
||||||
// If we're not in the middle of a parent chunk
|
|
||||||
if (_parentStack.Count == 0 || topLevel == true)
|
|
||||||
{
|
|
||||||
ChunkTree.Chunks.Add(chunk);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_parentStack.Peek().Children.Add(chunk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddTagHelperPrefixDirectiveChunk(string prefix, SyntaxTreeNode association)
|
|
||||||
{
|
|
||||||
AddChunk(
|
|
||||||
new TagHelperPrefixDirectiveChunk
|
|
||||||
{
|
|
||||||
Prefix = prefix
|
|
||||||
},
|
|
||||||
association,
|
|
||||||
topLevel: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddAddTagHelperChunk(string lookupText, SyntaxTreeNode association)
|
|
||||||
{
|
|
||||||
AddChunk(new AddTagHelperChunk
|
|
||||||
{
|
|
||||||
LookupText = lookupText
|
|
||||||
}, association, topLevel: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddRemoveTagHelperChunk(string lookupText, SyntaxTreeNode association)
|
|
||||||
{
|
|
||||||
AddChunk(new RemoveTagHelperChunk
|
|
||||||
{
|
|
||||||
LookupText = lookupText
|
|
||||||
}, association, topLevel: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddLiteralChunk(string literal, SyntaxTreeNode association)
|
|
||||||
{
|
|
||||||
// If the previous chunk was also a LiteralChunk, append the content of the current node to the previous one.
|
|
||||||
var literalChunk = _lastChunk as LiteralChunk;
|
|
||||||
if (literalChunk != null)
|
|
||||||
{
|
|
||||||
// Literal chunks are always associated with Spans
|
|
||||||
var lastSpan = (Span)literalChunk.Association;
|
|
||||||
var currentSpan = (Span)association;
|
|
||||||
|
|
||||||
var builder = new SpanBuilder(lastSpan);
|
|
||||||
foreach (var symbol in currentSpan.Symbols)
|
|
||||||
{
|
|
||||||
builder.Accept(symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
literalChunk.Association = builder.Build();
|
|
||||||
literalChunk.Text += literal;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddChunk(new LiteralChunk
|
|
||||||
{
|
|
||||||
Text = literal,
|
|
||||||
}, association);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddExpressionChunk(string expression, SyntaxTreeNode association)
|
|
||||||
{
|
|
||||||
AddChunk(new ExpressionChunk
|
|
||||||
{
|
|
||||||
Code = expression
|
|
||||||
}, association);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddStatementChunk(string code, SyntaxTreeNode association)
|
|
||||||
{
|
|
||||||
AddChunk(new StatementChunk
|
|
||||||
{
|
|
||||||
Code = code,
|
|
||||||
}, association);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddUsingChunk(string usingNamespace, SyntaxTreeNode association)
|
|
||||||
{
|
|
||||||
AddChunk(new UsingChunk
|
|
||||||
{
|
|
||||||
Namespace = usingNamespace,
|
|
||||||
}, association, topLevel: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddTypeMemberChunk(string code, SyntaxTreeNode association)
|
|
||||||
{
|
|
||||||
AddChunk(new TypeMemberChunk
|
|
||||||
{
|
|
||||||
Code = code,
|
|
||||||
}, association, topLevel: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddLiteralCodeAttributeChunk(string code, SyntaxTreeNode association)
|
|
||||||
{
|
|
||||||
AddChunk(new LiteralCodeAttributeChunk
|
|
||||||
{
|
|
||||||
Code = code,
|
|
||||||
}, association);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddSetBaseTypeChunk(string typeName, SyntaxTreeNode association)
|
|
||||||
{
|
|
||||||
AddChunk(new SetBaseTypeChunk
|
|
||||||
{
|
|
||||||
TypeName = typeName.Trim()
|
|
||||||
}, association, topLevel: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T StartParentChunk<T>(SyntaxTreeNode association) where T : ParentChunk, new()
|
|
||||||
{
|
|
||||||
return StartParentChunk<T>(association, topLevel: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T StartParentChunk<T>(SyntaxTreeNode association, bool topLevel) where T : ParentChunk, new()
|
|
||||||
{
|
|
||||||
var parentChunk = new T();
|
|
||||||
|
|
||||||
return StartParentChunk<T>(parentChunk, association, topLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T StartParentChunk<T>(T parentChunk, SyntaxTreeNode association, bool topLevel) where T : ParentChunk
|
|
||||||
{
|
|
||||||
AddChunk(parentChunk, association, topLevel);
|
|
||||||
|
|
||||||
_parentStack.Push(parentChunk);
|
|
||||||
|
|
||||||
return parentChunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void EndParentChunk()
|
|
||||||
{
|
|
||||||
_lastChunk = _parentStack.Pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.AspNet.Razor.Text;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
public class CodeAttributeChunk : ParentChunk
|
|
||||||
{
|
|
||||||
public string Attribute { get; set; }
|
|
||||||
public LocationTagged<string> Prefix { get; set; }
|
|
||||||
public LocationTagged<string> Suffix { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.AspNet.Razor.Text;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
public class DynamicCodeAttributeChunk : ParentChunk
|
|
||||||
{
|
|
||||||
public LocationTagged<string> Prefix { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
public class ExpressionBlockChunk : ParentChunk
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
public class ExpressionChunk : Chunk
|
|
||||||
{
|
|
||||||
public string Code { get; set; }
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return Start + " = " + Code;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public class AddImportChunkGenerator : SpanChunkGenerator
|
|
||||||
{
|
|
||||||
public AddImportChunkGenerator(string ns)
|
|
||||||
{
|
|
||||||
Namespace = ns;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Namespace { get; }
|
|
||||||
|
|
||||||
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
var ns = Namespace;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(ns) && char.IsWhiteSpace(ns[0]))
|
|
||||||
{
|
|
||||||
ns = ns.Substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.ChunkTreeBuilder.AddUsingChunk(ns, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return "Import:" + Namespace + ";";
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
var other = obj as AddImportChunkGenerator;
|
|
||||||
return other != null &&
|
|
||||||
string.Equals(Namespace, other.Namespace, StringComparison.Ordinal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
// Hash code should include only immutable properties.
|
|
||||||
return Namespace == null ? 0 : StringComparer.Ordinal.GetHashCode(Namespace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A <see cref="SpanChunkGenerator"/> responsible for generating <see cref="AddTagHelperChunk"/>s and
|
|
||||||
/// <see cref="RemoveTagHelperChunk"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public class AddOrRemoveTagHelperChunkGenerator : SpanChunkGenerator
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new <see cref="AddOrRemoveTagHelperChunkGenerator"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="lookupText">
|
|
||||||
/// Text used to look up <see cref="Compilation.TagHelpers.TagHelperDescriptor"/>s that should be added or removed.
|
|
||||||
/// </param>
|
|
||||||
public AddOrRemoveTagHelperChunkGenerator(bool removeTagHelperDescriptors, string lookupText)
|
|
||||||
{
|
|
||||||
RemoveTagHelperDescriptors = removeTagHelperDescriptors;
|
|
||||||
LookupText = lookupText;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the text used to look up <see cref="Compilation.TagHelpers.TagHelperDescriptor"/>s that should be added to or
|
|
||||||
/// removed from the Razor page.
|
|
||||||
/// </summary>
|
|
||||||
public string LookupText { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether we want to remove <see cref="Compilation.TagHelpers.TagHelperDescriptor"/>s from the Razor page.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>If <c>true</c> <see cref="GenerateChunk"/> generates <see cref="AddTagHelperChunk"/>s,
|
|
||||||
/// <see cref="RemoveTagHelperChunk"/>s otherwise.</remarks>
|
|
||||||
public bool RemoveTagHelperDescriptors { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates <see cref="AddTagHelperChunk"/>s if <see cref="RemoveTagHelperDescriptors"/> is
|
|
||||||
/// <c>true</c>, otherwise <see cref="RemoveTagHelperChunk"/>s are generated.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="target">
|
|
||||||
/// The <see cref="Span"/> responsible for this <see cref="AddOrRemoveTagHelperChunkGenerator"/>.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="context">A <see cref="ChunkGeneratorContext"/> instance that contains information about
|
|
||||||
/// the current chunk generation process.</param>
|
|
||||||
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
if (RemoveTagHelperDescriptors)
|
|
||||||
{
|
|
||||||
context.ChunkTreeBuilder.AddRemoveTagHelperChunk(LookupText, target);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
context.ChunkTreeBuilder.AddAddTagHelperChunk(LookupText, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Globalization;
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
using Microsoft.AspNet.Razor.Text;
|
|
||||||
using Microsoft.Extensions.Internal;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public class AttributeBlockChunkGenerator : ParentChunkGenerator
|
|
||||||
{
|
|
||||||
public AttributeBlockChunkGenerator(string name, LocationTagged<string> prefix, LocationTagged<string> suffix)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
Prefix = prefix;
|
|
||||||
Suffix = suffix;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name { get; }
|
|
||||||
|
|
||||||
public LocationTagged<string> Prefix { get; }
|
|
||||||
|
|
||||||
public LocationTagged<string> Suffix { get; }
|
|
||||||
|
|
||||||
public override void GenerateStartParentChunk(Block target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
var chunk = context.ChunkTreeBuilder.StartParentChunk<CodeAttributeChunk>(target);
|
|
||||||
|
|
||||||
chunk.Attribute = Name;
|
|
||||||
chunk.Prefix = Prefix;
|
|
||||||
chunk.Suffix = Suffix;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void GenerateEndParentChunk(Block target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
context.ChunkTreeBuilder.EndParentChunk();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, "Attr:{0},{1:F},{2:F}", Name, Prefix, Suffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
var other = obj as AttributeBlockChunkGenerator;
|
|
||||||
return other != null &&
|
|
||||||
string.Equals(other.Name, Name, StringComparison.Ordinal) &&
|
|
||||||
Equals(other.Prefix, Prefix) &&
|
|
||||||
Equals(other.Suffix, Suffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
var hashCodeCombiner = HashCodeCombiner.Start();
|
|
||||||
hashCodeCombiner.Add(Name, StringComparer.Ordinal);
|
|
||||||
hashCodeCombiner.Add(Prefix);
|
|
||||||
hashCodeCombiner.Add(Suffix);
|
|
||||||
|
|
||||||
return hashCodeCombiner;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public class ChunkGeneratorContext
|
|
||||||
{
|
|
||||||
protected ChunkGeneratorContext(ChunkGeneratorContext context)
|
|
||||||
: this(
|
|
||||||
context.Host,
|
|
||||||
context.ClassName,
|
|
||||||
context.RootNamespace,
|
|
||||||
context.SourceFile,
|
|
||||||
// True because we're pulling from the provided context's source file.
|
|
||||||
shouldGenerateLinePragmas: true)
|
|
||||||
{
|
|
||||||
ChunkTreeBuilder = context.ChunkTreeBuilder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChunkGeneratorContext(
|
|
||||||
RazorEngineHost host,
|
|
||||||
string className,
|
|
||||||
string rootNamespace,
|
|
||||||
string sourceFile,
|
|
||||||
bool shouldGenerateLinePragmas)
|
|
||||||
{
|
|
||||||
ChunkTreeBuilder = new ChunkTreeBuilder();
|
|
||||||
Host = host;
|
|
||||||
SourceFile = shouldGenerateLinePragmas ? sourceFile : null;
|
|
||||||
RootNamespace = rootNamespace;
|
|
||||||
ClassName = className;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string SourceFile { get; internal set; }
|
|
||||||
|
|
||||||
public string RootNamespace { get; }
|
|
||||||
|
|
||||||
public string ClassName { get; }
|
|
||||||
|
|
||||||
public RazorEngineHost Host { get; }
|
|
||||||
|
|
||||||
public ChunkTreeBuilder ChunkTreeBuilder { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Globalization;
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
using Microsoft.AspNet.Razor.Text;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public class DynamicAttributeBlockChunkGenerator : ParentChunkGenerator
|
|
||||||
{
|
|
||||||
public DynamicAttributeBlockChunkGenerator(LocationTagged<string> prefix, int offset, int line, int col)
|
|
||||||
: this(prefix, new SourceLocation(offset, line, col))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public DynamicAttributeBlockChunkGenerator(LocationTagged<string> prefix, SourceLocation valueStart)
|
|
||||||
{
|
|
||||||
Prefix = prefix;
|
|
||||||
ValueStart = valueStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocationTagged<string> Prefix { get; }
|
|
||||||
|
|
||||||
public SourceLocation ValueStart { get; }
|
|
||||||
|
|
||||||
public override void GenerateStartParentChunk(Block target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
var chunk = context.ChunkTreeBuilder.StartParentChunk<DynamicCodeAttributeChunk>(target);
|
|
||||||
chunk.Start = ValueStart;
|
|
||||||
chunk.Prefix = Prefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void GenerateEndParentChunk(Block target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
context.ChunkTreeBuilder.EndParentChunk();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, "DynAttr:{0:F}", Prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
var other = obj as DynamicAttributeBlockChunkGenerator;
|
|
||||||
return other != null &&
|
|
||||||
Equals(other.Prefix, Prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return Prefix == null ? 0 : Prefix.GetHashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public class ExpressionChunkGenerator : ISpanChunkGenerator, IParentChunkGenerator
|
|
||||||
{
|
|
||||||
private static readonly int TypeHashCode = typeof(ExpressionChunkGenerator).GetHashCode();
|
|
||||||
|
|
||||||
public void GenerateStartParentChunk(Block target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
context.ChunkTreeBuilder.StartParentChunk<ExpressionBlockChunk>(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GenerateChunk(Span target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
context.ChunkTreeBuilder.AddExpressionChunk(target.Content, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GenerateEndParentChunk(Block target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
context.ChunkTreeBuilder.EndParentChunk();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return "Expr";
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
return obj != null &&
|
|
||||||
GetType() == obj.GetType();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return TypeHashCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public interface IParentChunkGenerator
|
|
||||||
{
|
|
||||||
void GenerateStartParentChunk(Block target, ChunkGeneratorContext context);
|
|
||||||
void GenerateEndParentChunk(Block target, ChunkGeneratorContext context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public interface ISpanChunkGenerator
|
|
||||||
{
|
|
||||||
void GenerateChunk(Span target, ChunkGeneratorContext context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,83 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Globalization;
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
using Microsoft.AspNet.Razor.Text;
|
|
||||||
using Microsoft.Extensions.Internal;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public class LiteralAttributeChunkGenerator : SpanChunkGenerator
|
|
||||||
{
|
|
||||||
public LiteralAttributeChunkGenerator(
|
|
||||||
LocationTagged<string> prefix,
|
|
||||||
LocationTagged<SpanChunkGenerator> valueGenerator)
|
|
||||||
{
|
|
||||||
Prefix = prefix;
|
|
||||||
ValueGenerator = valueGenerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiteralAttributeChunkGenerator(LocationTagged<string> prefix, LocationTagged<string> value)
|
|
||||||
{
|
|
||||||
Prefix = prefix;
|
|
||||||
Value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocationTagged<string> Prefix { get; }
|
|
||||||
|
|
||||||
public LocationTagged<string> Value { get; }
|
|
||||||
|
|
||||||
public LocationTagged<SpanChunkGenerator> ValueGenerator { get; }
|
|
||||||
|
|
||||||
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
var chunk = context.ChunkTreeBuilder.StartParentChunk<LiteralCodeAttributeChunk>(target);
|
|
||||||
chunk.Prefix = Prefix;
|
|
||||||
chunk.Value = Value;
|
|
||||||
|
|
||||||
if (ValueGenerator != null)
|
|
||||||
{
|
|
||||||
chunk.ValueLocation = ValueGenerator.Location;
|
|
||||||
|
|
||||||
ValueGenerator.Value.GenerateChunk(target, context);
|
|
||||||
|
|
||||||
chunk.ValueLocation = ValueGenerator.Location;
|
|
||||||
}
|
|
||||||
|
|
||||||
context.ChunkTreeBuilder.EndParentChunk();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
if (ValueGenerator == null)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, "LitAttr:{0:F},{1:F}", Prefix, Value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, "LitAttr:{0:F},<Sub:{1:F}>", Prefix, ValueGenerator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
var other = obj as LiteralAttributeChunkGenerator;
|
|
||||||
return other != null &&
|
|
||||||
Equals(other.Prefix, Prefix) &&
|
|
||||||
Equals(other.Value, Value) &&
|
|
||||||
Equals(other.ValueGenerator, ValueGenerator);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
var hashCodeCombiner = HashCodeCombiner.Start();
|
|
||||||
|
|
||||||
hashCodeCombiner.Add(Prefix);
|
|
||||||
hashCodeCombiner.Add(Value);
|
|
||||||
hashCodeCombiner.Add(ValueGenerator);
|
|
||||||
|
|
||||||
return hashCodeCombiner;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public class MarkupChunkGenerator : SpanChunkGenerator
|
|
||||||
{
|
|
||||||
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
context.ChunkTreeBuilder.AddLiteralChunk(target.Content, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return "Markup";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public abstract class ParentChunkGenerator : IParentChunkGenerator
|
|
||||||
{
|
|
||||||
private static readonly int TypeHashCode = typeof(ParentChunkGenerator).GetHashCode();
|
|
||||||
|
|
||||||
[SuppressMessage(
|
|
||||||
"Microsoft.Security",
|
|
||||||
"CA2104:DoNotDeclareReadOnlyMutableReferenceTypes",
|
|
||||||
Justification = "This class has no instance state")]
|
|
||||||
public static readonly IParentChunkGenerator Null = new NullParentChunkGenerator();
|
|
||||||
|
|
||||||
public virtual void GenerateStartParentChunk(Block target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void GenerateEndParentChunk(Block target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
return obj != null &&
|
|
||||||
GetType() == obj.GetType();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return TypeHashCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class NullParentChunkGenerator : IParentChunkGenerator
|
|
||||||
{
|
|
||||||
public void GenerateStartParentChunk(Block target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GenerateEndParentChunk(Block target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return "None";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.AspNet.Razor.Parser;
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public class RazorChunkGenerator : ParserVisitor
|
|
||||||
{
|
|
||||||
private ChunkGeneratorContext _context;
|
|
||||||
|
|
||||||
public RazorChunkGenerator(
|
|
||||||
string className,
|
|
||||||
string rootNamespaceName,
|
|
||||||
string sourceFileName,
|
|
||||||
RazorEngineHost host)
|
|
||||||
{
|
|
||||||
if (rootNamespaceName == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(rootNamespaceName));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (host == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(host));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(className))
|
|
||||||
{
|
|
||||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, nameof(className));
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassName = className;
|
|
||||||
RootNamespaceName = rootNamespaceName;
|
|
||||||
SourceFileName = sourceFileName;
|
|
||||||
GenerateLinePragmas = string.IsNullOrEmpty(SourceFileName) ? false : true;
|
|
||||||
Host = host;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Data pulled from constructor
|
|
||||||
public string ClassName { get; private set; }
|
|
||||||
public string RootNamespaceName { get; private set; }
|
|
||||||
public string SourceFileName { get; private set; }
|
|
||||||
public RazorEngineHost Host { get; private set; }
|
|
||||||
|
|
||||||
// Generation settings
|
|
||||||
public bool GenerateLinePragmas { get; set; }
|
|
||||||
public bool DesignTimeMode { get; set; }
|
|
||||||
|
|
||||||
public ChunkGeneratorContext Context
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
EnsureContextInitialized();
|
|
||||||
return _context;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void VisitStartBlock(Block block)
|
|
||||||
{
|
|
||||||
block.ChunkGenerator.GenerateStartParentChunk(block, Context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void VisitEndBlock(Block block)
|
|
||||||
{
|
|
||||||
block.ChunkGenerator.GenerateEndParentChunk(block, Context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void VisitSpan(Span span)
|
|
||||||
{
|
|
||||||
span.ChunkGenerator.GenerateChunk(span, Context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EnsureContextInitialized()
|
|
||||||
{
|
|
||||||
if (_context == null)
|
|
||||||
{
|
|
||||||
_context = new ChunkGeneratorContext(Host,
|
|
||||||
ClassName,
|
|
||||||
RootNamespaceName,
|
|
||||||
SourceFileName,
|
|
||||||
GenerateLinePragmas);
|
|
||||||
Initialize(_context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Initialize(ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public class RazorCommentChunkGenerator : ParentChunkGenerator
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public class SectionChunkGenerator : ParentChunkGenerator
|
|
||||||
{
|
|
||||||
public SectionChunkGenerator(string sectionName)
|
|
||||||
{
|
|
||||||
SectionName = sectionName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string SectionName { get; }
|
|
||||||
|
|
||||||
public override void GenerateStartParentChunk(Block target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
var chunk = context.ChunkTreeBuilder.StartParentChunk<SectionChunk>(target);
|
|
||||||
|
|
||||||
chunk.Name = SectionName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void GenerateEndParentChunk(Block target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
context.ChunkTreeBuilder.EndParentChunk();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
var other = obj as SectionChunkGenerator;
|
|
||||||
return base.Equals(other) &&
|
|
||||||
string.Equals(SectionName, other.SectionName, StringComparison.Ordinal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return SectionName == null ? 0 : StringComparer.Ordinal.GetHashCode(SectionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return "Section:" + SectionName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public class SetBaseTypeChunkGenerator : SpanChunkGenerator
|
|
||||||
{
|
|
||||||
public SetBaseTypeChunkGenerator(string baseType)
|
|
||||||
{
|
|
||||||
BaseType = baseType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string BaseType { get; }
|
|
||||||
|
|
||||||
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
context.ChunkTreeBuilder.AddSetBaseTypeChunk(BaseType, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return "Base:" + BaseType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
var other = obj as SetBaseTypeChunkGenerator;
|
|
||||||
return other != null &&
|
|
||||||
string.Equals(BaseType, other.BaseType, StringComparison.Ordinal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return BaseType.GetHashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public abstract class SpanChunkGenerator : ISpanChunkGenerator
|
|
||||||
{
|
|
||||||
private static readonly int TypeHashCode = typeof(SpanChunkGenerator).GetHashCode();
|
|
||||||
|
|
||||||
[SuppressMessage(
|
|
||||||
"Microsoft.Security",
|
|
||||||
"CA2104:DoNotDeclareReadOnlyMutableReferenceTypes",
|
|
||||||
Justification = "This class has no instance state")]
|
|
||||||
public static readonly ISpanChunkGenerator Null = new NullSpanChunkGenerator();
|
|
||||||
|
|
||||||
public virtual void GenerateChunk(Span target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
return obj != null &&
|
|
||||||
GetType() == obj.GetType();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return TypeHashCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class NullSpanChunkGenerator : ISpanChunkGenerator
|
|
||||||
{
|
|
||||||
public void GenerateChunk(Span target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return "None";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public class StatementChunkGenerator : SpanChunkGenerator
|
|
||||||
{
|
|
||||||
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
context.ChunkTreeBuilder.AddStatementChunk(target.Content, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return "Stmt";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,107 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
using Microsoft.AspNet.Razor.Parser.TagHelpers;
|
|
||||||
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A <see cref="ParentChunkGenerator"/> that is responsible for generating valid <see cref="TagHelperChunk"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public class TagHelperChunkGenerator : ParentChunkGenerator
|
|
||||||
{
|
|
||||||
private IEnumerable<TagHelperDescriptor> _tagHelperDescriptors;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new <see cref="TagHelperChunkGenerator"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tagHelperDescriptors">
|
|
||||||
/// <see cref="TagHelperDescriptor"/>s associated with the current HTML tag.
|
|
||||||
/// </param>
|
|
||||||
public TagHelperChunkGenerator(IEnumerable<TagHelperDescriptor> tagHelperDescriptors)
|
|
||||||
{
|
|
||||||
_tagHelperDescriptors = tagHelperDescriptors;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Starts the generation of a <see cref="TagHelperChunk"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="target">
|
|
||||||
/// The <see cref="Block"/> responsible for this <see cref="TagHelperChunkGenerator"/>.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="context">A <see cref="ChunkGeneratorContext"/> instance that contains information about
|
|
||||||
/// the current chunk generation process.</param>
|
|
||||||
public override void GenerateStartParentChunk(Block target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
var tagHelperBlock = target as TagHelperBlock;
|
|
||||||
|
|
||||||
Debug.Assert(
|
|
||||||
tagHelperBlock != null,
|
|
||||||
$"A {nameof(TagHelperChunkGenerator)} must only be used with {nameof(TagHelperBlock)}s.");
|
|
||||||
|
|
||||||
var attributes = new List<KeyValuePair<string, Chunk>>();
|
|
||||||
|
|
||||||
// We need to create a chunk generator to create chunks for each of the attributes.
|
|
||||||
var chunkGenerator = context.Host.CreateChunkGenerator(
|
|
||||||
context.ClassName,
|
|
||||||
context.RootNamespace,
|
|
||||||
context.SourceFile);
|
|
||||||
|
|
||||||
foreach (var attribute in tagHelperBlock.Attributes)
|
|
||||||
{
|
|
||||||
ParentChunk attributeChunkValue = null;
|
|
||||||
|
|
||||||
if (attribute.Value != null)
|
|
||||||
{
|
|
||||||
// Populates the chunk tree with chunks associated with attributes
|
|
||||||
attribute.Value.Accept(chunkGenerator);
|
|
||||||
|
|
||||||
var chunks = chunkGenerator.Context.ChunkTreeBuilder.ChunkTree.Chunks;
|
|
||||||
var first = chunks.FirstOrDefault();
|
|
||||||
|
|
||||||
attributeChunkValue = new ParentChunk
|
|
||||||
{
|
|
||||||
Association = first?.Association,
|
|
||||||
Children = chunks,
|
|
||||||
Start = first == null ? SourceLocation.Zero : first.Start
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
attributes.Add(new KeyValuePair<string, Chunk>(attribute.Key, attributeChunkValue));
|
|
||||||
|
|
||||||
// Reset the chunk tree builder so we can build a new one for the next attribute
|
|
||||||
chunkGenerator.Context.ChunkTreeBuilder = new ChunkTreeBuilder();
|
|
||||||
}
|
|
||||||
|
|
||||||
var unprefixedTagName = tagHelperBlock.TagName.Substring(_tagHelperDescriptors.First().Prefix.Length);
|
|
||||||
|
|
||||||
context.ChunkTreeBuilder.StartParentChunk(
|
|
||||||
new TagHelperChunk(
|
|
||||||
unprefixedTagName,
|
|
||||||
tagHelperBlock.TagMode,
|
|
||||||
attributes,
|
|
||||||
_tagHelperDescriptors),
|
|
||||||
target,
|
|
||||||
topLevel: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ends the generation of a <see cref="TagHelperChunk"/> capturing all previously visited children
|
|
||||||
/// since the <see cref="GenerateStartParentChunk"/> method was called.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="target">
|
|
||||||
/// The <see cref="Block"/> responsible for this <see cref="TagHelperChunkGenerator"/>.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="context">A <see cref="ChunkGeneratorContext"/> instance that contains information about
|
|
||||||
/// the current chunk generation process.</param>
|
|
||||||
public override void GenerateEndParentChunk(Block target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
context.ChunkTreeBuilder.EndParentChunk();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A <see cref="SpanChunkGenerator"/> responsible for generating
|
|
||||||
/// <see cref="TagHelperPrefixDirectiveChunk"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public class TagHelperPrefixDirectiveChunkGenerator : SpanChunkGenerator
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new <see cref="TagHelperPrefixDirectiveChunkGenerator"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="prefix">
|
|
||||||
/// Text used as a required prefix when matching HTML.
|
|
||||||
/// </param>
|
|
||||||
public TagHelperPrefixDirectiveChunkGenerator(string prefix)
|
|
||||||
{
|
|
||||||
Prefix = prefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Text used as a required prefix when matching HTML.
|
|
||||||
/// </summary>
|
|
||||||
public string Prefix { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates <see cref="TagHelperPrefixDirectiveChunk"/>s.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="target">
|
|
||||||
/// The <see cref="Span"/> responsible for this <see cref="TagHelperPrefixDirectiveChunkGenerator"/>.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="context">A <see cref="ChunkGeneratorContext"/> instance that contains information about
|
|
||||||
/// the current chunk generation process.</param>
|
|
||||||
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
context.ChunkTreeBuilder.AddTagHelperPrefixDirectiveChunk(Prefix, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public class TemplateBlockChunkGenerator : ParentChunkGenerator
|
|
||||||
{
|
|
||||||
public override void GenerateStartParentChunk(Block target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
context.ChunkTreeBuilder.StartParentChunk<TemplateChunk>(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void GenerateEndParentChunk(Block target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
context.ChunkTreeBuilder.EndParentChunk();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks.Generators
|
|
||||||
{
|
|
||||||
public class TypeMemberChunkGenerator : SpanChunkGenerator
|
|
||||||
{
|
|
||||||
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
context.ChunkTreeBuilder.AddTypeMemberChunk(target.Content, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return "TypeMember";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
public class LiteralChunk : Chunk
|
|
||||||
{
|
|
||||||
public string Text { get; set; }
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return Start + " = " + Text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.AspNet.Razor.Text;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
public class LiteralCodeAttributeChunk : ParentChunk
|
|
||||||
{
|
|
||||||
public string Code { get; set; }
|
|
||||||
public LocationTagged<string> Prefix { get; set; }
|
|
||||||
public LocationTagged<string> Value { get; set; }
|
|
||||||
public SourceLocation ValueLocation { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
public class ParentChunk : Chunk
|
|
||||||
{
|
|
||||||
public ParentChunk()
|
|
||||||
{
|
|
||||||
Children = new List<Chunk>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IList<Chunk> Children { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A <see cref="Chunk"/> used to look up <see cref="Compilation.TagHelpers.TagHelperDescriptor"/>s that should be ignored
|
|
||||||
/// within the Razor page.
|
|
||||||
/// </summary>
|
|
||||||
public class RemoveTagHelperChunk : Chunk
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Text used to look up <see cref="Compilation.TagHelpers.TagHelperDescriptor"/>s that should be ignored within the Razor
|
|
||||||
/// page.
|
|
||||||
/// </summary>
|
|
||||||
public string LookupText { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
public class SectionChunk : ParentChunk
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
public class SetBaseTypeChunk : Chunk
|
|
||||||
{
|
|
||||||
public string TypeName { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
public class StatementChunk : Chunk
|
|
||||||
{
|
|
||||||
public string Code { get; set; }
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return Start + " = " + Code;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Microsoft.AspNet.Razor.TagHelpers;
|
|
||||||
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A <see cref="ParentChunk"/> that represents a special HTML tag.
|
|
||||||
/// </summary>
|
|
||||||
public class TagHelperChunk : ParentChunk
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new <see cref="TagHelperChunk"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tagName">The tag name associated with the tag helpers HTML element.</param>
|
|
||||||
/// <param name="tagMode">HTML syntax of the element in the Razor source.</param>
|
|
||||||
/// <param name="attributes">The attributes associated with the tag helpers HTML element.</param>
|
|
||||||
/// <param name="descriptors">
|
|
||||||
/// The <see cref="TagHelperDescriptor"/>s associated with this tag helpers HTML element.
|
|
||||||
/// </param>
|
|
||||||
public TagHelperChunk(
|
|
||||||
string tagName,
|
|
||||||
TagMode tagMode,
|
|
||||||
IList<KeyValuePair<string, Chunk>> attributes,
|
|
||||||
IEnumerable<TagHelperDescriptor> descriptors)
|
|
||||||
{
|
|
||||||
TagName = tagName;
|
|
||||||
TagMode = tagMode;
|
|
||||||
Attributes = attributes;
|
|
||||||
Descriptors = descriptors;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The HTML attributes.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// These attributes are <see cref="string"/> => <see cref="Chunk"/> so attribute values can consist
|
|
||||||
/// of all sorts of Razor specific pieces.
|
|
||||||
/// </remarks>
|
|
||||||
public IList<KeyValuePair<string, Chunk>> Attributes { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The <see cref="TagHelperDescriptor"/>s that are associated with the tag helpers HTML element.
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<TagHelperDescriptor> Descriptors { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The HTML tag name.
|
|
||||||
/// </summary>
|
|
||||||
public string TagName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the HTML syntax of the element in the Razor source.
|
|
||||||
/// </summary>
|
|
||||||
public TagMode TagMode { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A <see cref="Chunk"/> for the <c>@tagHelperPrefix</c> directive.
|
|
||||||
/// </summary>
|
|
||||||
public class TagHelperPrefixDirectiveChunk : Chunk
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Text used as a required prefix when matching HTML start and end tags in the Razor source to available
|
|
||||||
/// tag helpers.
|
|
||||||
/// </summary>
|
|
||||||
public string Prefix { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
public class TemplateChunk : ParentChunk
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
public class TypeMemberChunk : Chunk
|
|
||||||
{
|
|
||||||
public string Code { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Chunks
|
|
||||||
{
|
|
||||||
public class UsingChunk : Chunk
|
|
||||||
{
|
|
||||||
public string Namespace { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,177 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNet.Razor.Chunks;
|
|
||||||
using Microsoft.AspNet.Razor.CodeGenerators.Visitors;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
public class CSharpCodeGenerator : CodeGenerator
|
|
||||||
{
|
|
||||||
// See http://msdn.microsoft.com/en-us/library/system.codedom.codechecksumpragma.checksumalgorithmid.aspx
|
|
||||||
private const string Sha1AlgorithmId = "{ff1816ec-aa5e-4d10-87f7-6f4963833460}";
|
|
||||||
private const int DisableAsyncWarning = 1998;
|
|
||||||
|
|
||||||
public CSharpCodeGenerator(CodeGeneratorContext context)
|
|
||||||
: base(context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private ChunkTree Tree { get { return Context.ChunkTreeBuilder.ChunkTree; } }
|
|
||||||
public RazorEngineHost Host { get { return Context.Host; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Protected for testing.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A new instance of <see cref="CSharpCodeWriter"/>.</returns>
|
|
||||||
protected virtual CSharpCodeWriter CreateCodeWriter()
|
|
||||||
{
|
|
||||||
return new CSharpCodeWriter();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override CodeGeneratorResult Generate()
|
|
||||||
{
|
|
||||||
var writer = CreateCodeWriter();
|
|
||||||
|
|
||||||
if (!Host.DesignTimeMode && !string.IsNullOrEmpty(Context.Checksum))
|
|
||||||
{
|
|
||||||
writer.Write("#pragma checksum \"")
|
|
||||||
.Write(Context.SourceFile)
|
|
||||||
.Write("\" \"")
|
|
||||||
.Write(Sha1AlgorithmId)
|
|
||||||
.Write("\" \"")
|
|
||||||
.Write(Context.Checksum)
|
|
||||||
.WriteLine("\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
using (writer.BuildNamespace(Context.RootNamespace))
|
|
||||||
{
|
|
||||||
// Write out using directives
|
|
||||||
AddImports(Tree, writer, Host.NamespaceImports);
|
|
||||||
// Separate the usings and the class
|
|
||||||
writer.WriteLine();
|
|
||||||
|
|
||||||
using (BuildClassDeclaration(writer))
|
|
||||||
{
|
|
||||||
if (Host.DesignTimeMode)
|
|
||||||
{
|
|
||||||
writer.WriteLine("private static object @__o;");
|
|
||||||
}
|
|
||||||
|
|
||||||
var csharpCodeVisitor = CreateCSharpCodeVisitor(writer, Context);
|
|
||||||
|
|
||||||
new CSharpTypeMemberVisitor(csharpCodeVisitor, writer, Context).Accept(Tree.Chunks);
|
|
||||||
CreateCSharpDesignTimeCodeVisitor(csharpCodeVisitor, writer, Context)
|
|
||||||
.AcceptTree(Tree);
|
|
||||||
new CSharpTagHelperFieldDeclarationVisitor(writer, Context).Accept(Tree.Chunks);
|
|
||||||
|
|
||||||
BuildConstructor(writer);
|
|
||||||
|
|
||||||
// Add space in-between constructor and method body
|
|
||||||
writer.WriteLine();
|
|
||||||
|
|
||||||
using (writer.BuildDisableWarningScope(DisableAsyncWarning))
|
|
||||||
{
|
|
||||||
using (writer.BuildMethodDeclaration("public override async", "Task", Host.GeneratedClassContext.ExecuteMethodName))
|
|
||||||
{
|
|
||||||
new CSharpTagHelperRunnerInitializationVisitor(writer, Context).Accept(Tree.Chunks);
|
|
||||||
csharpCodeVisitor.Accept(Tree.Chunks);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CodeGeneratorResult(writer.GenerateCode(), writer.LineMappingManager.Mappings);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual CSharpCodeVisitor CreateCSharpCodeVisitor(
|
|
||||||
CSharpCodeWriter writer,
|
|
||||||
CodeGeneratorContext context)
|
|
||||||
{
|
|
||||||
if (writer == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(writer));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CSharpCodeVisitor(writer, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual CSharpDesignTimeCodeVisitor CreateCSharpDesignTimeCodeVisitor(
|
|
||||||
CSharpCodeVisitor csharpCodeVisitor,
|
|
||||||
CSharpCodeWriter writer,
|
|
||||||
CodeGeneratorContext context)
|
|
||||||
{
|
|
||||||
if (csharpCodeVisitor == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(csharpCodeVisitor));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (writer == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(writer));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CSharpDesignTimeCodeVisitor(csharpCodeVisitor, writer, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual CSharpCodeWritingScope BuildClassDeclaration(CSharpCodeWriter writer)
|
|
||||||
{
|
|
||||||
var baseTypeVisitor = new CSharpBaseTypeVisitor(writer, Context);
|
|
||||||
baseTypeVisitor.Accept(Tree.Chunks);
|
|
||||||
|
|
||||||
var baseType = baseTypeVisitor.CurrentBaseType ?? Host.DefaultBaseClass;
|
|
||||||
|
|
||||||
var baseTypes = string.IsNullOrEmpty(baseType) ? Enumerable.Empty<string>() : new string[] { baseType };
|
|
||||||
|
|
||||||
return writer.BuildClassDeclaration("public", Context.ClassName, baseTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void BuildConstructor(CSharpCodeWriter writer)
|
|
||||||
{
|
|
||||||
writer.WriteLineHiddenDirective();
|
|
||||||
using (writer.BuildConstructor(Context.ClassName))
|
|
||||||
{
|
|
||||||
// Any constructor based logic that we need to add?
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddImports(ChunkTree chunkTree, CSharpCodeWriter writer, IEnumerable<string> defaultImports)
|
|
||||||
{
|
|
||||||
// Write out using directives
|
|
||||||
var usingVisitor = new CSharpUsingVisitor(writer, Context);
|
|
||||||
foreach (Chunk chunk in Tree.Chunks)
|
|
||||||
{
|
|
||||||
usingVisitor.Accept(chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultImports = defaultImports.Except(usingVisitor.ImportedUsings);
|
|
||||||
|
|
||||||
foreach (string import in defaultImports)
|
|
||||||
{
|
|
||||||
writer.WriteUsing(import);
|
|
||||||
}
|
|
||||||
|
|
||||||
var taskNamespace = typeof(Task).Namespace;
|
|
||||||
|
|
||||||
// We need to add the task namespace but ONLY if it hasn't been added by the default imports or using imports yet.
|
|
||||||
if (!defaultImports.Contains(taskNamespace) && !usingVisitor.ImportedUsings.Contains(taskNamespace))
|
|
||||||
{
|
|
||||||
writer.WriteUsing(taskNamespace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,513 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.AspNet.Razor.Chunks.Generators;
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
using Microsoft.AspNet.Razor.Text;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
public class CSharpCodeWriter : CodeWriter
|
|
||||||
{
|
|
||||||
private const string InstanceMethodFormat = "{0}.{1}";
|
|
||||||
|
|
||||||
public CSharpCodeWriter()
|
|
||||||
{
|
|
||||||
LineMappingManager = new LineMappingManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
public LineMappingManager LineMappingManager { get; private set; }
|
|
||||||
|
|
||||||
public new CSharpCodeWriter Write(string data)
|
|
||||||
{
|
|
||||||
return (CSharpCodeWriter)base.Write(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public new CSharpCodeWriter Indent(int size)
|
|
||||||
{
|
|
||||||
return (CSharpCodeWriter)base.Indent(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
public new CSharpCodeWriter ResetIndent()
|
|
||||||
{
|
|
||||||
return (CSharpCodeWriter)base.ResetIndent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public new CSharpCodeWriter SetIndent(int size)
|
|
||||||
{
|
|
||||||
return (CSharpCodeWriter)base.SetIndent(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
public new CSharpCodeWriter IncreaseIndent(int size)
|
|
||||||
{
|
|
||||||
return (CSharpCodeWriter)base.IncreaseIndent(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
public new CSharpCodeWriter DecreaseIndent(int size)
|
|
||||||
{
|
|
||||||
return (CSharpCodeWriter)base.DecreaseIndent(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
public new CSharpCodeWriter WriteLine(string data)
|
|
||||||
{
|
|
||||||
return (CSharpCodeWriter)base.WriteLine(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public new CSharpCodeWriter WriteLine()
|
|
||||||
{
|
|
||||||
return (CSharpCodeWriter)base.WriteLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteVariableDeclaration(string type, string name, string value)
|
|
||||||
{
|
|
||||||
Write(type).Write(" ").Write(name);
|
|
||||||
if (!string.IsNullOrEmpty(value))
|
|
||||||
{
|
|
||||||
Write(" = ").Write(value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Write(" = null");
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteLine(";");
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteComment(string comment)
|
|
||||||
{
|
|
||||||
return Write("// ").WriteLine(comment);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteBooleanLiteral(bool value)
|
|
||||||
{
|
|
||||||
return Write(value.ToString().ToLowerInvariant());
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteStartAssignment(string name)
|
|
||||||
{
|
|
||||||
return Write(name).Write(" = ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteParameterSeparator()
|
|
||||||
{
|
|
||||||
return Write(", ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteStartNewObject(string typeName)
|
|
||||||
{
|
|
||||||
return Write("new ").Write(typeName).Write("(");
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteLocationTaggedString(LocationTagged<string> value)
|
|
||||||
{
|
|
||||||
WriteStringLiteral(value.Value);
|
|
||||||
WriteParameterSeparator();
|
|
||||||
Write(value.Location.AbsoluteIndex.ToString(CultureInfo.CurrentCulture));
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteStringLiteral(string literal)
|
|
||||||
{
|
|
||||||
if (literal.Length >= 256 && literal.Length <= 1500 && literal.IndexOf('\0') == -1)
|
|
||||||
{
|
|
||||||
WriteVerbatimStringLiteral(literal);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteCStyleStringLiteral(literal);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteLineHiddenDirective()
|
|
||||||
{
|
|
||||||
return WriteLine("#line hidden");
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WritePragma(string value)
|
|
||||||
{
|
|
||||||
return Write("#pragma ").WriteLine(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteUsing(string name)
|
|
||||||
{
|
|
||||||
return WriteUsing(name, endLine: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteUsing(string name, bool endLine)
|
|
||||||
{
|
|
||||||
Write(string.Format("using {0}", name));
|
|
||||||
|
|
||||||
if (endLine)
|
|
||||||
{
|
|
||||||
WriteLine(";");
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteLineDefaultDirective()
|
|
||||||
{
|
|
||||||
return WriteLine("#line default");
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteStartReturn()
|
|
||||||
{
|
|
||||||
return Write("return ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteReturn(string value)
|
|
||||||
{
|
|
||||||
return WriteReturn(value, endLine: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteReturn(string value, bool endLine)
|
|
||||||
{
|
|
||||||
Write("return ").Write(value);
|
|
||||||
|
|
||||||
if (endLine)
|
|
||||||
{
|
|
||||||
Write(";");
|
|
||||||
}
|
|
||||||
|
|
||||||
return WriteLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Writes a <c>#line</c> pragma directive for the line number at the specified <paramref name="location"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="location">The location to generate the line pragma for.</param>
|
|
||||||
/// <param name="file">The file to generate the line pragma for.</param>
|
|
||||||
/// <returns>The current instance of <see cref="CSharpCodeWriter"/>.</returns>
|
|
||||||
public CSharpCodeWriter WriteLineNumberDirective(SourceLocation location, string file)
|
|
||||||
{
|
|
||||||
if (location.FilePath != null)
|
|
||||||
{
|
|
||||||
file = location.FilePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(LastWrite) &&
|
|
||||||
!LastWrite.EndsWith(NewLine, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
WriteLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
var lineNumberAsString = (location.LineIndex + 1).ToString(CultureInfo.InvariantCulture);
|
|
||||||
return Write("#line ").Write(lineNumberAsString).Write(" \"").Write(file).WriteLine("\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteStartMethodInvocation(string methodName)
|
|
||||||
{
|
|
||||||
return WriteStartMethodInvocation(methodName, new string[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteStartMethodInvocation(string methodName, params string[] genericArguments)
|
|
||||||
{
|
|
||||||
Write(methodName);
|
|
||||||
|
|
||||||
if (genericArguments.Length > 0)
|
|
||||||
{
|
|
||||||
Write("<").Write(string.Join(", ", genericArguments)).Write(">");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Write("(");
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteEndMethodInvocation()
|
|
||||||
{
|
|
||||||
return WriteEndMethodInvocation(endLine: true);
|
|
||||||
}
|
|
||||||
public CSharpCodeWriter WriteEndMethodInvocation(bool endLine)
|
|
||||||
{
|
|
||||||
Write(")");
|
|
||||||
if (endLine)
|
|
||||||
{
|
|
||||||
WriteLine(";");
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes a method invocation for the given instance name.
|
|
||||||
public CSharpCodeWriter WriteInstanceMethodInvocation(string instanceName,
|
|
||||||
string methodName,
|
|
||||||
params string[] parameters)
|
|
||||||
{
|
|
||||||
if (instanceName == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(instanceName));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (methodName == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(methodName));
|
|
||||||
}
|
|
||||||
|
|
||||||
return WriteInstanceMethodInvocation(instanceName, methodName, endLine: true, parameters: parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes a method invocation for the given instance name.
|
|
||||||
public CSharpCodeWriter WriteInstanceMethodInvocation(string instanceName,
|
|
||||||
string methodName,
|
|
||||||
bool endLine,
|
|
||||||
params string[] parameters)
|
|
||||||
{
|
|
||||||
if (instanceName == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(instanceName));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (methodName == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(methodName));
|
|
||||||
}
|
|
||||||
|
|
||||||
return WriteMethodInvocation(
|
|
||||||
string.Format(CultureInfo.InvariantCulture, InstanceMethodFormat, instanceName, methodName),
|
|
||||||
endLine,
|
|
||||||
parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteStartInstanceMethodInvocation(string instanceName,
|
|
||||||
string methodName)
|
|
||||||
{
|
|
||||||
if (instanceName == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(instanceName));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (methodName == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(methodName));
|
|
||||||
}
|
|
||||||
|
|
||||||
return WriteStartMethodInvocation(
|
|
||||||
string.Format(CultureInfo.InvariantCulture, InstanceMethodFormat, instanceName, methodName));
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteMethodInvocation(string methodName, params string[] parameters)
|
|
||||||
{
|
|
||||||
return WriteMethodInvocation(methodName, endLine: true, parameters: parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteMethodInvocation(string methodName, bool endLine, params string[] parameters)
|
|
||||||
{
|
|
||||||
return WriteStartMethodInvocation(methodName).Write(string.Join(", ", parameters)).WriteEndMethodInvocation(endLine);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpDisableWarningScope BuildDisableWarningScope(int warning)
|
|
||||||
{
|
|
||||||
return new CSharpDisableWarningScope(this, warning);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWritingScope BuildScope()
|
|
||||||
{
|
|
||||||
return new CSharpCodeWritingScope(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWritingScope BuildLambda(bool endLine, params string[] parameterNames)
|
|
||||||
{
|
|
||||||
return BuildLambda(endLine, async: false, parameterNames: parameterNames);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWritingScope BuildAsyncLambda(bool endLine, params string[] parameterNames)
|
|
||||||
{
|
|
||||||
return BuildLambda(endLine, async: true, parameterNames: parameterNames);
|
|
||||||
}
|
|
||||||
|
|
||||||
private CSharpCodeWritingScope BuildLambda(bool endLine, bool async, string[] parameterNames)
|
|
||||||
{
|
|
||||||
if (async)
|
|
||||||
{
|
|
||||||
Write("async");
|
|
||||||
}
|
|
||||||
|
|
||||||
Write("(").Write(string.Join(", ", parameterNames)).Write(") => ");
|
|
||||||
|
|
||||||
var scope = new CSharpCodeWritingScope(this);
|
|
||||||
|
|
||||||
if (endLine)
|
|
||||||
{
|
|
||||||
// End the lambda with a semicolon
|
|
||||||
scope.OnClose += () =>
|
|
||||||
{
|
|
||||||
WriteLine(";");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWritingScope BuildNamespace(string name)
|
|
||||||
{
|
|
||||||
Write("namespace ").WriteLine(name);
|
|
||||||
|
|
||||||
return new CSharpCodeWritingScope(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWritingScope BuildClassDeclaration(string accessibility, string name)
|
|
||||||
{
|
|
||||||
return BuildClassDeclaration(accessibility, name, Enumerable.Empty<string>());
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWritingScope BuildClassDeclaration(string accessibility, string name, string baseType)
|
|
||||||
{
|
|
||||||
return BuildClassDeclaration(accessibility, name, new string[] { baseType });
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWritingScope BuildClassDeclaration(string accessibility, string name, IEnumerable<string> baseTypes)
|
|
||||||
{
|
|
||||||
Write(accessibility).Write(" class ").Write(name);
|
|
||||||
|
|
||||||
if (baseTypes.Count() > 0)
|
|
||||||
{
|
|
||||||
Write(" : ");
|
|
||||||
Write(string.Join(", ", baseTypes));
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteLine();
|
|
||||||
|
|
||||||
return new CSharpCodeWritingScope(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWritingScope BuildConstructor(string name)
|
|
||||||
{
|
|
||||||
return BuildConstructor("public", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWritingScope BuildConstructor(string accessibility, string name)
|
|
||||||
{
|
|
||||||
return BuildConstructor(accessibility, name, Enumerable.Empty<KeyValuePair<string, string>>());
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWritingScope BuildConstructor(string accessibility, string name, IEnumerable<KeyValuePair<string, string>> parameters)
|
|
||||||
{
|
|
||||||
Write(accessibility).Write(" ").Write(name).Write("(").Write(string.Join(", ", parameters.Select(p => p.Key + " " + p.Value))).WriteLine(")");
|
|
||||||
|
|
||||||
return new CSharpCodeWritingScope(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWritingScope BuildMethodDeclaration(string accessibility, string returnType, string name)
|
|
||||||
{
|
|
||||||
return BuildMethodDeclaration(accessibility, returnType, name, Enumerable.Empty<KeyValuePair<string, string>>());
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWritingScope BuildMethodDeclaration(string accessibility, string returnType, string name, IEnumerable<KeyValuePair<string, string>> parameters)
|
|
||||||
{
|
|
||||||
Write(accessibility).Write(" ").Write(returnType).Write(" ").Write(name).Write("(").Write(string.Join(", ", parameters.Select(p => p.Key + " " + p.Value))).WriteLine(")");
|
|
||||||
|
|
||||||
return new CSharpCodeWritingScope(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Do I need to look at the document content to determine its mapping length?
|
|
||||||
public CSharpLineMappingWriter BuildLineMapping(SourceLocation documentLocation, int contentLength, string sourceFilename)
|
|
||||||
{
|
|
||||||
return new CSharpLineMappingWriter(this, documentLocation, contentLength, sourceFilename);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteVerbatimStringLiteral(string literal)
|
|
||||||
{
|
|
||||||
Write("@\"");
|
|
||||||
|
|
||||||
foreach (char c in literal)
|
|
||||||
{
|
|
||||||
if (c == '\"')
|
|
||||||
{
|
|
||||||
Write("\"\"");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Write(c.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write("\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteCStyleStringLiteral(string literal)
|
|
||||||
{
|
|
||||||
// From CSharpCodeGenerator.QuoteSnippetStringCStyle in CodeDOM
|
|
||||||
Write("\"");
|
|
||||||
for (int i = 0; i < literal.Length; i++)
|
|
||||||
{
|
|
||||||
switch (literal[i])
|
|
||||||
{
|
|
||||||
case '\r':
|
|
||||||
Write("\\r");
|
|
||||||
break;
|
|
||||||
case '\t':
|
|
||||||
Write("\\t");
|
|
||||||
break;
|
|
||||||
case '\"':
|
|
||||||
Write("\\\"");
|
|
||||||
break;
|
|
||||||
case '\'':
|
|
||||||
Write("\\\'");
|
|
||||||
break;
|
|
||||||
case '\\':
|
|
||||||
Write("\\\\");
|
|
||||||
break;
|
|
||||||
case '\0':
|
|
||||||
Write("\\\0");
|
|
||||||
break;
|
|
||||||
case '\n':
|
|
||||||
Write("\\n");
|
|
||||||
break;
|
|
||||||
case '\u2028':
|
|
||||||
case '\u2029':
|
|
||||||
Write("\\u");
|
|
||||||
Write(((int)literal[i]).ToString("X4", CultureInfo.InvariantCulture));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Write(literal[i].ToString());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i > 0 && i % 80 == 0)
|
|
||||||
{
|
|
||||||
// If current character is a high surrogate and the following
|
|
||||||
// character is a low surrogate, don't break them.
|
|
||||||
// Otherwise when we write the string to a file, we might lose
|
|
||||||
// the characters.
|
|
||||||
if (Char.IsHighSurrogate(literal[i])
|
|
||||||
&& (i < literal.Length - 1)
|
|
||||||
&& Char.IsLowSurrogate(literal[i + 1]))
|
|
||||||
{
|
|
||||||
Write(literal[++i].ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
Write("\" +");
|
|
||||||
Write(NewLine);
|
|
||||||
Write("\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Write("\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteStartInstrumentationContext(
|
|
||||||
ChunkGeneratorContext context,
|
|
||||||
SyntaxTreeNode syntaxNode,
|
|
||||||
bool isLiteral)
|
|
||||||
{
|
|
||||||
WriteStartMethodInvocation(context.Host.GeneratedClassContext.BeginContextMethodName);
|
|
||||||
Write(syntaxNode.Start.AbsoluteIndex.ToString(CultureInfo.InvariantCulture));
|
|
||||||
WriteParameterSeparator();
|
|
||||||
Write(syntaxNode.Length.ToString(CultureInfo.InvariantCulture));
|
|
||||||
WriteParameterSeparator();
|
|
||||||
Write(isLiteral ? "true" : "false");
|
|
||||||
return WriteEndMethodInvocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpCodeWriter WriteEndInstrumentationContext(ChunkGeneratorContext context)
|
|
||||||
{
|
|
||||||
return WriteMethodInvocation(context.Host.GeneratedClassContext.EndContextMethodName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
public struct CSharpCodeWritingScope : IDisposable
|
|
||||||
{
|
|
||||||
private CodeWriter _writer;
|
|
||||||
private bool _autoSpace;
|
|
||||||
private int _tabSize;
|
|
||||||
private int _startIndent;
|
|
||||||
|
|
||||||
public CSharpCodeWritingScope(CodeWriter writer) : this(writer, true) { }
|
|
||||||
public CSharpCodeWritingScope(CodeWriter writer, int tabSize) : this(writer, tabSize, true) { }
|
|
||||||
// TODO: Make indents (tabs) environment specific
|
|
||||||
public CSharpCodeWritingScope(CodeWriter writer, bool autoSpace) : this(writer, 4, autoSpace) { }
|
|
||||||
public CSharpCodeWritingScope(CodeWriter writer, int tabSize, bool autoSpace)
|
|
||||||
{
|
|
||||||
_writer = writer;
|
|
||||||
_autoSpace = true;
|
|
||||||
_tabSize = tabSize;
|
|
||||||
_startIndent = -1; // Set in WriteStartScope
|
|
||||||
|
|
||||||
OnClose = () => { };
|
|
||||||
|
|
||||||
WriteStartScope();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Action OnClose;
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
WriteEndScope();
|
|
||||||
OnClose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteStartScope()
|
|
||||||
{
|
|
||||||
TryAutoSpace(" ");
|
|
||||||
|
|
||||||
_writer.WriteLine("{").IncreaseIndent(_tabSize);
|
|
||||||
_startIndent = _writer.CurrentIndent;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteEndScope()
|
|
||||||
{
|
|
||||||
TryAutoSpace(_writer.NewLine);
|
|
||||||
|
|
||||||
// Ensure the scope hasn't been modified
|
|
||||||
if (_writer.CurrentIndent == _startIndent)
|
|
||||||
{
|
|
||||||
_writer.DecreaseIndent(_tabSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
_writer.WriteLine("}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TryAutoSpace(string spaceCharacter)
|
|
||||||
{
|
|
||||||
if (_autoSpace && _writer.LastWrite.Length > 0 && !Char.IsWhiteSpace(_writer.LastWrite.Last()))
|
|
||||||
{
|
|
||||||
_writer.Write(spaceCharacter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
public struct CSharpDisableWarningScope : IDisposable
|
|
||||||
{
|
|
||||||
private CSharpCodeWriter _writer;
|
|
||||||
int _warningNumber;
|
|
||||||
|
|
||||||
public CSharpDisableWarningScope(CSharpCodeWriter writer) : this(writer, 219)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
public CSharpDisableWarningScope(CSharpCodeWriter writer, int warningNumber)
|
|
||||||
{
|
|
||||||
_writer = writer;
|
|
||||||
_warningNumber = warningNumber;
|
|
||||||
|
|
||||||
_writer.WritePragma("warning disable " + _warningNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_writer.WritePragma("warning restore " + _warningNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,136 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
public class CSharpLineMappingWriter : IDisposable
|
|
||||||
{
|
|
||||||
private readonly CSharpCodeWriter _writer;
|
|
||||||
private readonly MappingLocation _documentMapping;
|
|
||||||
private readonly int _startIndent;
|
|
||||||
private readonly bool _writePragmas;
|
|
||||||
private readonly bool _addLineMapping;
|
|
||||||
|
|
||||||
private SourceLocation _generatedLocation;
|
|
||||||
private int _generatedContentLength;
|
|
||||||
|
|
||||||
private CSharpLineMappingWriter(CSharpCodeWriter writer, bool addLineMappings)
|
|
||||||
{
|
|
||||||
if (writer == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(writer));
|
|
||||||
}
|
|
||||||
|
|
||||||
_writer = writer;
|
|
||||||
_addLineMapping = addLineMappings;
|
|
||||||
_startIndent = _writer.CurrentIndent;
|
|
||||||
_writer.ResetIndent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpLineMappingWriter(CSharpCodeWriter writer, SourceLocation documentLocation, int contentLength)
|
|
||||||
: this(writer, addLineMappings: true)
|
|
||||||
{
|
|
||||||
_documentMapping = new MappingLocation(documentLocation, contentLength);
|
|
||||||
_generatedLocation = _writer.GetCurrentSourceLocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSharpLineMappingWriter(
|
|
||||||
CSharpCodeWriter writer,
|
|
||||||
SourceLocation documentLocation,
|
|
||||||
int contentLength,
|
|
||||||
string sourceFilename)
|
|
||||||
: this(writer, documentLocation, contentLength)
|
|
||||||
{
|
|
||||||
_writePragmas = true;
|
|
||||||
|
|
||||||
_writer.WriteLineNumberDirective(documentLocation, sourceFilename);
|
|
||||||
_generatedLocation = _writer.GetCurrentSourceLocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of <see cref="CSharpLineMappingWriter"/> used for generation of runtime
|
|
||||||
/// line mappings. The constructed instance of <see cref="CSharpLineMappingWriter"/> does not track
|
|
||||||
/// mappings between the Razor content and the generated content.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="writer">The <see cref="CSharpCodeWriter"/> to write output to.</param>
|
|
||||||
/// <param name="documentLocation">The <see cref="SourceLocation"/> of the Razor content being mapping.</param>
|
|
||||||
/// <param name="sourceFileName">The input file path.</param>
|
|
||||||
public CSharpLineMappingWriter(
|
|
||||||
CSharpCodeWriter writer,
|
|
||||||
SourceLocation documentLocation,
|
|
||||||
string sourceFileName)
|
|
||||||
: this(writer, addLineMappings: false)
|
|
||||||
{
|
|
||||||
if (writer == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(writer));
|
|
||||||
}
|
|
||||||
|
|
||||||
_writePragmas = true;
|
|
||||||
_writer.WriteLineNumberDirective(documentLocation, sourceFileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MarkLineMappingStart()
|
|
||||||
{
|
|
||||||
_generatedLocation = _writer.GetCurrentSourceLocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MarkLineMappingEnd()
|
|
||||||
{
|
|
||||||
_generatedContentLength = _writer.GenerateCode().Length - _generatedLocation.AbsoluteIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (_addLineMapping)
|
|
||||||
{
|
|
||||||
// Verify that the generated length has not already been calculated
|
|
||||||
if (_generatedContentLength == 0)
|
|
||||||
{
|
|
||||||
_generatedContentLength = _writer.GenerateCode().Length - _generatedLocation.AbsoluteIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
var generatedLocation = new MappingLocation(_generatedLocation, _generatedContentLength);
|
|
||||||
var documentMapping = _documentMapping;
|
|
||||||
if (documentMapping.ContentLength == -1)
|
|
||||||
{
|
|
||||||
documentMapping = new MappingLocation(
|
|
||||||
location: new SourceLocation(
|
|
||||||
_documentMapping.FilePath,
|
|
||||||
_documentMapping.AbsoluteIndex,
|
|
||||||
_documentMapping.LineIndex,
|
|
||||||
_documentMapping.CharacterIndex),
|
|
||||||
contentLength: _generatedContentLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
_writer.LineMappingManager.AddMapping(
|
|
||||||
documentLocation: documentMapping,
|
|
||||||
generatedLocation: generatedLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_writePragmas)
|
|
||||||
{
|
|
||||||
// Need to add an additional line at the end IF there wasn't one already written.
|
|
||||||
// This is needed to work with the C# editor's handling of #line ...
|
|
||||||
var endsWithNewline = _writer.GenerateCode().EndsWith("\n");
|
|
||||||
|
|
||||||
// Always write at least 1 empty line to potentially separate code from pragmas.
|
|
||||||
_writer.WriteLine();
|
|
||||||
|
|
||||||
// Check if the previous empty line wasn't enough to separate code from pragmas.
|
|
||||||
if (!endsWithNewline)
|
|
||||||
{
|
|
||||||
_writer.WriteLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
_writer.WriteLineDefaultDirective()
|
|
||||||
.WriteLineHiddenDirective();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset indent back to when it was started
|
|
||||||
_writer.SetIndent(_startIndent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,180 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.AspNet.Razor.Parser;
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
public class CSharpPaddingBuilder
|
|
||||||
{
|
|
||||||
private static readonly char[] _newLineChars = { '\r', '\n' };
|
|
||||||
|
|
||||||
private readonly RazorEngineHost _host;
|
|
||||||
|
|
||||||
public CSharpPaddingBuilder(RazorEngineHost host)
|
|
||||||
{
|
|
||||||
_host = host;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special case for statement padding to account for brace positioning in the editor.
|
|
||||||
public string BuildStatementPadding(Span target)
|
|
||||||
{
|
|
||||||
if (target == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(target));
|
|
||||||
}
|
|
||||||
|
|
||||||
var padding = CalculatePadding(target, generatedStart: 0);
|
|
||||||
|
|
||||||
// We treat statement padding specially so for brace positioning, so that in the following example:
|
|
||||||
// @if (foo > 0)
|
|
||||||
// {
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// the braces shows up under the @ rather than under the if.
|
|
||||||
if (_host.DesignTimeMode &&
|
|
||||||
padding > 0 &&
|
|
||||||
target.Previous.Kind == SpanKind.Transition && // target.Previous is guaranteed to not be null if you have padding.
|
|
||||||
string.Equals(target.Previous.Content, SyntaxConstants.TransitionString, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
padding--;
|
|
||||||
}
|
|
||||||
|
|
||||||
var generatedCode = BuildPaddingInternal(padding);
|
|
||||||
|
|
||||||
return generatedCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string BuildExpressionPadding(Span target)
|
|
||||||
{
|
|
||||||
return BuildExpressionPadding(target, generatedStart: 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string BuildExpressionPadding(Span target, int generatedStart)
|
|
||||||
{
|
|
||||||
if (target == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(target));
|
|
||||||
}
|
|
||||||
|
|
||||||
var padding = CalculatePadding(target, generatedStart);
|
|
||||||
|
|
||||||
return BuildPaddingInternal(padding);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal int CalculatePadding(Span target, int generatedStart)
|
|
||||||
{
|
|
||||||
if (target == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(target));
|
|
||||||
}
|
|
||||||
|
|
||||||
int padding;
|
|
||||||
|
|
||||||
padding = CollectSpacesAndTabs(target, _host.TabSize) - generatedStart;
|
|
||||||
|
|
||||||
// if we add generated text that is longer than the padding we wanted to insert we have no recourse and we have to skip padding
|
|
||||||
// example:
|
|
||||||
// Razor code at column zero: @somecode()
|
|
||||||
// Generated code will be:
|
|
||||||
// In design time: __o = somecode();
|
|
||||||
// In Run time: Write(somecode());
|
|
||||||
//
|
|
||||||
// In both cases the padding would have been 1 space to remote the space the @ symbol takes, which will be smaller than the 6
|
|
||||||
// chars the hidden generated code takes.
|
|
||||||
if (padding < 0)
|
|
||||||
{
|
|
||||||
padding = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string BuildPaddingInternal(int padding)
|
|
||||||
{
|
|
||||||
if (_host.DesignTimeMode && _host.IsIndentingWithTabs)
|
|
||||||
{
|
|
||||||
var spaces = padding % _host.TabSize;
|
|
||||||
var tabs = padding / _host.TabSize;
|
|
||||||
|
|
||||||
return new string('\t', tabs) + new string(' ', spaces);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new string(' ', padding);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int CollectSpacesAndTabs(Span target, int tabSize)
|
|
||||||
{
|
|
||||||
var firstSpanInLine = target;
|
|
||||||
|
|
||||||
string currentContent = null;
|
|
||||||
|
|
||||||
while (firstSpanInLine.Previous != null)
|
|
||||||
{
|
|
||||||
// When scanning previous spans we need to be break down the spans with spaces. The parser combines
|
|
||||||
// whitespace into existing spans so you'll see tabs, newlines etc. within spans. We only care about
|
|
||||||
// the \t in existing spans.
|
|
||||||
var previousContent = firstSpanInLine.Previous.Content ?? string.Empty;
|
|
||||||
|
|
||||||
var lastNewLineIndex = previousContent.LastIndexOfAny(_newLineChars);
|
|
||||||
|
|
||||||
if (lastNewLineIndex < 0)
|
|
||||||
{
|
|
||||||
firstSpanInLine = firstSpanInLine.Previous;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (lastNewLineIndex != previousContent.Length - 1)
|
|
||||||
{
|
|
||||||
firstSpanInLine = firstSpanInLine.Previous;
|
|
||||||
currentContent = previousContent.Substring(lastNewLineIndex + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to walk from the beginning of the line, because space + tab(tabSize) = tabSize columns, but tab(tabSize) + space = tabSize+1 columns.
|
|
||||||
var currentSpanInLine = firstSpanInLine;
|
|
||||||
|
|
||||||
if (currentContent == null)
|
|
||||||
{
|
|
||||||
currentContent = currentSpanInLine.Content;
|
|
||||||
}
|
|
||||||
|
|
||||||
var padding = 0;
|
|
||||||
while (currentSpanInLine != target)
|
|
||||||
{
|
|
||||||
if (currentContent != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < currentContent.Length; i++)
|
|
||||||
{
|
|
||||||
if (currentContent[i] == '\t')
|
|
||||||
{
|
|
||||||
// Example:
|
|
||||||
// <space><space><tab><tab>:
|
|
||||||
// iter 1) 1
|
|
||||||
// iter 2) 2
|
|
||||||
// iter 3) 4 = 2 + (4 - 2)
|
|
||||||
// iter 4) 8 = 4 + (4 - 0)
|
|
||||||
padding = padding + (tabSize - (padding % tabSize));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
padding++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
currentSpanInLine = currentSpanInLine.Next;
|
|
||||||
currentContent = currentSpanInLine.Content;
|
|
||||||
}
|
|
||||||
|
|
||||||
return padding;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,761 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.AspNet.Razor.Chunks;
|
|
||||||
using Microsoft.AspNet.Razor.CodeGenerators.Visitors;
|
|
||||||
using Microsoft.AspNet.Razor.TagHelpers;
|
|
||||||
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Renders tag helper rendering code.
|
|
||||||
/// </summary>
|
|
||||||
public class CSharpTagHelperCodeRenderer
|
|
||||||
{
|
|
||||||
internal static readonly string ExecutionContextVariableName = "__tagHelperExecutionContext";
|
|
||||||
internal static readonly string StringValueBufferVariableName = "__tagHelperStringValueBuffer";
|
|
||||||
internal static readonly string ScopeManagerVariableName = "__tagHelperScopeManager";
|
|
||||||
internal static readonly string RunnerVariableName = "__tagHelperRunner";
|
|
||||||
|
|
||||||
private readonly CSharpCodeWriter _writer;
|
|
||||||
private readonly CodeGeneratorContext _context;
|
|
||||||
private readonly IChunkVisitor _bodyVisitor;
|
|
||||||
private readonly IChunkVisitor _literalBodyVisitor;
|
|
||||||
private readonly TagHelperAttributeCodeVisitor _attributeCodeVisitor;
|
|
||||||
private readonly GeneratedTagHelperContext _tagHelperContext;
|
|
||||||
private readonly bool _designTimeMode;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new <see cref="CSharpTagHelperCodeRenderer"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="bodyVisitor">The <see cref="IChunkVisitor"/> used to render chunks found in the body.</param>
|
|
||||||
/// <param name="writer">The <see cref="CSharpCodeWriter"/> used to write code.</param>
|
|
||||||
/// <param name="context">A <see cref="CodeGeneratorContext"/> instance that contains information about
|
|
||||||
/// the current code generation process.</param>
|
|
||||||
public CSharpTagHelperCodeRenderer(
|
|
||||||
IChunkVisitor bodyVisitor,
|
|
||||||
CSharpCodeWriter writer,
|
|
||||||
CodeGeneratorContext context)
|
|
||||||
{
|
|
||||||
if (bodyVisitor == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(bodyVisitor));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (writer == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(writer));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
_bodyVisitor = bodyVisitor;
|
|
||||||
_writer = writer;
|
|
||||||
_context = context;
|
|
||||||
_tagHelperContext = context.Host.GeneratedClassContext.GeneratedTagHelperContext;
|
|
||||||
_designTimeMode = context.Host.DesignTimeMode;
|
|
||||||
|
|
||||||
_literalBodyVisitor = new CSharpLiteralCodeVisitor(this, writer, context);
|
|
||||||
_attributeCodeVisitor = new TagHelperAttributeCodeVisitor(writer, context);
|
|
||||||
AttributeValueCodeRenderer = new TagHelperAttributeValueCodeRenderer();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TagHelperAttributeValueCodeRenderer AttributeValueCodeRenderer { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Renders the code for the given <paramref name="chunk"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="chunk">A <see cref="TagHelperChunk"/> to render.</param>
|
|
||||||
public void RenderTagHelper(TagHelperChunk chunk)
|
|
||||||
{
|
|
||||||
// Remove any duplicate TagHelperDescriptors that reference the same type name. Duplicates can occur when
|
|
||||||
// multiple HtmlTargetElement attributes are on a TagHelper type and matches overlap for an HTML element.
|
|
||||||
// Having more than one descriptor with the same TagHelper type results in generated code that runs
|
|
||||||
// the same TagHelper X many times (instead of once) over a single HTML element.
|
|
||||||
var tagHelperDescriptors = chunk.Descriptors.Distinct(TypeBasedTagHelperDescriptorComparer.Default);
|
|
||||||
|
|
||||||
RenderBeginTagHelperScope(chunk.TagName, chunk.TagMode, chunk.Children);
|
|
||||||
|
|
||||||
RenderTagHelpersCreation(chunk, tagHelperDescriptors);
|
|
||||||
|
|
||||||
RenderAttributes(chunk.Attributes, tagHelperDescriptors);
|
|
||||||
|
|
||||||
// No need to run anything in design time mode.
|
|
||||||
if (!_designTimeMode)
|
|
||||||
{
|
|
||||||
RenderRunTagHelpers();
|
|
||||||
RenderWriteTagHelperMethodCall(chunk);
|
|
||||||
RenderEndTagHelpersScope();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static string GetVariableName(TagHelperDescriptor descriptor)
|
|
||||||
{
|
|
||||||
return "__" + descriptor.TypeName.Replace('.', '_');
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RenderBeginTagHelperScope(string tagName, TagMode tagMode, 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call into the tag helper scope manager to start a new tag helper scope.
|
|
||||||
// Also capture the value as the current execution context.
|
|
||||||
_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()
|
|
||||||
.Write(nameof(TagMode))
|
|
||||||
.Write(".")
|
|
||||||
.Write(tagMode.ToString())
|
|
||||||
.WriteParameterSeparator()
|
|
||||||
.WriteStringLiteral(GenerateUniqueId())
|
|
||||||
.WriteParameterSeparator();
|
|
||||||
|
|
||||||
// We remove the target writer so TagHelper authors can retrieve content.
|
|
||||||
var oldWriter = _context.TargetWriterName;
|
|
||||||
_context.TargetWriterName = null;
|
|
||||||
|
|
||||||
using (_writer.BuildAsyncLambda(endLine: false))
|
|
||||||
{
|
|
||||||
// Render all of the tag helper children.
|
|
||||||
_bodyVisitor.Accept(children);
|
|
||||||
}
|
|
||||||
|
|
||||||
_context.TargetWriterName = oldWriter;
|
|
||||||
|
|
||||||
_writer.WriteParameterSeparator()
|
|
||||||
.Write(_tagHelperContext.StartTagHelperWritingScopeMethodName)
|
|
||||||
.WriteParameterSeparator()
|
|
||||||
.Write(_tagHelperContext.EndTagHelperWritingScopeMethodName)
|
|
||||||
.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,
|
|
||||||
IEnumerable<TagHelperDescriptor> tagHelperDescriptors)
|
|
||||||
{
|
|
||||||
// This is to maintain value accessors for attributes when creating the TagHelpers.
|
|
||||||
// Ultimately it enables us to do scenarios like this:
|
|
||||||
// myTagHelper1.Foo = DateTime.Now;
|
|
||||||
// myTagHelper2.Foo = myTagHelper1.Foo;
|
|
||||||
var htmlAttributeValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
foreach (var tagHelperDescriptor in tagHelperDescriptors)
|
|
||||||
{
|
|
||||||
var tagHelperVariableName = GetVariableName(tagHelperDescriptor);
|
|
||||||
|
|
||||||
// Create the tag helper
|
|
||||||
_writer.WriteStartAssignment(tagHelperVariableName)
|
|
||||||
.WriteStartMethodInvocation(_tagHelperContext.CreateTagHelperMethodName,
|
|
||||||
tagHelperDescriptor.TypeName)
|
|
||||||
.WriteEndMethodInvocation();
|
|
||||||
|
|
||||||
// Execution contexts and throwing errors for null dictionary properties are a runtime feature.
|
|
||||||
if (_designTimeMode)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
_writer.WriteInstanceMethodInvocation(
|
|
||||||
ExecutionContextVariableName,
|
|
||||||
_tagHelperContext.ExecutionContextAddMethodName,
|
|
||||||
tagHelperVariableName);
|
|
||||||
|
|
||||||
// Track dictionary properties we have confirmed are non-null.
|
|
||||||
var confirmedDictionaries = new HashSet<string>(StringComparer.Ordinal);
|
|
||||||
|
|
||||||
// Ensure that all created TagHelpers have initialized dictionary bound properties which are used
|
|
||||||
// via TagHelper indexers.
|
|
||||||
foreach (var chunkAttribute in chunk.Attributes)
|
|
||||||
{
|
|
||||||
var associatedAttributeDescriptor = tagHelperDescriptor.Attributes.FirstOrDefault(
|
|
||||||
attributeDescriptor => attributeDescriptor.IsNameMatch(chunkAttribute.Key));
|
|
||||||
|
|
||||||
if (associatedAttributeDescriptor != null &&
|
|
||||||
associatedAttributeDescriptor.IsIndexer &&
|
|
||||||
confirmedDictionaries.Add(associatedAttributeDescriptor.PropertyName))
|
|
||||||
{
|
|
||||||
// Throw a reasonable Exception at runtime if the dictionary property is null.
|
|
||||||
_writer
|
|
||||||
.Write("if (")
|
|
||||||
.Write(tagHelperVariableName)
|
|
||||||
.Write(".")
|
|
||||||
.Write(associatedAttributeDescriptor.PropertyName)
|
|
||||||
.WriteLine(" == null)");
|
|
||||||
using (_writer.BuildScope())
|
|
||||||
{
|
|
||||||
// System is in Host.NamespaceImports for all MVC scenarios. No need to generate FullName
|
|
||||||
// of InvalidOperationException type.
|
|
||||||
_writer
|
|
||||||
.Write("throw ")
|
|
||||||
.WriteStartNewObject(nameof(InvalidOperationException))
|
|
||||||
.WriteStartMethodInvocation(_tagHelperContext.FormatInvalidIndexerAssignmentMethodName)
|
|
||||||
.WriteStringLiteral(chunkAttribute.Key)
|
|
||||||
.WriteParameterSeparator()
|
|
||||||
.WriteStringLiteral(tagHelperDescriptor.TypeName)
|
|
||||||
.WriteParameterSeparator()
|
|
||||||
.WriteStringLiteral(associatedAttributeDescriptor.PropertyName)
|
|
||||||
.WriteEndMethodInvocation(endLine: false) // End of method call
|
|
||||||
.WriteEndMethodInvocation(endLine: true); // End of new expression / throw statement
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RenderAttributes(
|
|
||||||
IList<KeyValuePair<string, Chunk>> chunkAttributes,
|
|
||||||
IEnumerable<TagHelperDescriptor> tagHelperDescriptors)
|
|
||||||
{
|
|
||||||
var renderedBoundAttributeNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
// Go through the HTML attributes in source order, assigning to properties or indexers or adding to
|
|
||||||
// TagHelperExecutionContext.HTMLAttributes' as we go.
|
|
||||||
foreach (var attribute in chunkAttributes)
|
|
||||||
{
|
|
||||||
var attributeName = attribute.Key;
|
|
||||||
var attributeValueChunk = attribute.Value;
|
|
||||||
var associatedDescriptors = tagHelperDescriptors.Where(descriptor =>
|
|
||||||
descriptor.Attributes.Any(attributeDescriptor => attributeDescriptor.IsNameMatch(attributeName)));
|
|
||||||
|
|
||||||
// Bound attributes have associated descriptors. First attribute value wins if there are duplicates;
|
|
||||||
// later values of duplicate bound attributes are treated as if they were unbound.
|
|
||||||
if (associatedDescriptors.Any() && renderedBoundAttributeNames.Add(attributeName))
|
|
||||||
{
|
|
||||||
if (attributeValueChunk == null)
|
|
||||||
{
|
|
||||||
// Minimized attributes are not valid for bound attributes. TagHelperBlockRewriter has already
|
|
||||||
// logged an error if it was a bound attribute; so we can skip.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to capture the tag helper's property value accessor so we can retrieve it later
|
|
||||||
// if there are more tag helpers that need the value.
|
|
||||||
string valueAccessor = null;
|
|
||||||
|
|
||||||
foreach (var associatedDescriptor in associatedDescriptors)
|
|
||||||
{
|
|
||||||
var associatedAttributeDescriptor = associatedDescriptor.Attributes.First(
|
|
||||||
attributeDescriptor => attributeDescriptor.IsNameMatch(attributeName));
|
|
||||||
var tagHelperVariableName = GetVariableName(associatedDescriptor);
|
|
||||||
|
|
||||||
valueAccessor = RenderBoundAttribute(
|
|
||||||
attributeName,
|
|
||||||
attributeValueChunk,
|
|
||||||
tagHelperVariableName,
|
|
||||||
valueAccessor,
|
|
||||||
associatedAttributeDescriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RenderUnboundAttribute(attributeName, attributeValueChunk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string RenderBoundAttribute(
|
|
||||||
string attributeName,
|
|
||||||
Chunk attributeValueChunk,
|
|
||||||
string tagHelperVariableName,
|
|
||||||
string previousValueAccessor,
|
|
||||||
TagHelperAttributeDescriptor attributeDescriptor)
|
|
||||||
{
|
|
||||||
var currentValueAccessor = string.Format(
|
|
||||||
CultureInfo.InvariantCulture,
|
|
||||||
"{0}.{1}",
|
|
||||||
tagHelperVariableName,
|
|
||||||
attributeDescriptor.PropertyName);
|
|
||||||
|
|
||||||
if (attributeDescriptor.IsIndexer)
|
|
||||||
{
|
|
||||||
var dictionaryKey = attributeName.Substring(attributeDescriptor.Name.Length);
|
|
||||||
currentValueAccessor += $"[\"{dictionaryKey}\"]";
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this attribute value has not been seen before, need to record its value.
|
|
||||||
if (previousValueAccessor == null)
|
|
||||||
{
|
|
||||||
// Bufferable attributes are attributes that can have Razor code inside of them. Such
|
|
||||||
// attributes have string values and may be calculated using a temporary TextWriter or other
|
|
||||||
// buffer.
|
|
||||||
var bufferableAttribute = attributeDescriptor.IsStringProperty;
|
|
||||||
|
|
||||||
RenderNewAttributeValueAssignment(
|
|
||||||
attributeDescriptor,
|
|
||||||
bufferableAttribute,
|
|
||||||
attributeValueChunk,
|
|
||||||
currentValueAccessor);
|
|
||||||
|
|
||||||
if (_designTimeMode)
|
|
||||||
{
|
|
||||||
// Execution contexts are a runtime feature.
|
|
||||||
return currentValueAccessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to inform the context of the attribute value.
|
|
||||||
_writer
|
|
||||||
.WriteStartInstanceMethodInvocation(
|
|
||||||
ExecutionContextVariableName,
|
|
||||||
_tagHelperContext.ExecutionContextAddTagHelperAttributeMethodName)
|
|
||||||
.WriteStringLiteral(attributeName)
|
|
||||||
.WriteParameterSeparator()
|
|
||||||
.Write(currentValueAccessor)
|
|
||||||
.WriteEndMethodInvocation();
|
|
||||||
|
|
||||||
return currentValueAccessor;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// The attribute value has already been determined and accessor was passed to us as
|
|
||||||
// previousValueAccessor, we don't want to evaluate the value twice so lets just use the
|
|
||||||
// previousValueLocation.
|
|
||||||
_writer
|
|
||||||
.WriteStartAssignment(currentValueAccessor)
|
|
||||||
.Write(previousValueAccessor)
|
|
||||||
.WriteLine(";");
|
|
||||||
|
|
||||||
return previousValueAccessor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render assignment of attribute value to the value accessor.
|
|
||||||
private void RenderNewAttributeValueAssignment(
|
|
||||||
TagHelperAttributeDescriptor attributeDescriptor,
|
|
||||||
bool bufferableAttribute,
|
|
||||||
Chunk attributeValueChunk,
|
|
||||||
string valueAccessor)
|
|
||||||
{
|
|
||||||
// Plain text values are non Razor code (@DateTime.Now) values. If an attribute is bufferable it
|
|
||||||
// may be more than just a plain text value, it may also contain Razor code which is why we attempt
|
|
||||||
// to retrieve a plain text value here.
|
|
||||||
string textValue;
|
|
||||||
var isPlainTextValue = TryGetPlainTextValue(attributeValueChunk, out textValue);
|
|
||||||
|
|
||||||
if (bufferableAttribute)
|
|
||||||
{
|
|
||||||
if (!isPlainTextValue)
|
|
||||||
{
|
|
||||||
// If we haven't recorded a value and we need to buffer an attribute value and the value is not
|
|
||||||
// plain text then we need to prepare the value prior to setting it below.
|
|
||||||
BuildBufferedWritingScope(attributeValueChunk, htmlEncodeValues: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
_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. stringAttribute ="Time: @DateTime.Now".
|
|
||||||
RenderBufferedAttributeValue(attributeDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
_writer.WriteLine(";");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 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(";");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RenderUnboundAttribute(string attributeName, Chunk attributeValueChunk)
|
|
||||||
{
|
|
||||||
// Render children to provide IntelliSense at design time. No need for the execution context logic, it's
|
|
||||||
// a runtime feature.
|
|
||||||
if (_designTimeMode)
|
|
||||||
{
|
|
||||||
if (attributeValueChunk != null)
|
|
||||||
{
|
|
||||||
_bodyVisitor.Accept(attributeValueChunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have a minimized attribute there is no value
|
|
||||||
if (attributeValueChunk == null)
|
|
||||||
{
|
|
||||||
_writer
|
|
||||||
.WriteStartInstanceMethodInvocation(
|
|
||||||
ExecutionContextVariableName,
|
|
||||||
_tagHelperContext.ExecutionContextAddMinimizedHtmlAttributeMethodName)
|
|
||||||
.WriteStringLiteral(attributeName)
|
|
||||||
.WriteEndMethodInvocation();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string textValue = null;
|
|
||||||
var isPlainTextValue = TryGetPlainTextValue(attributeValueChunk, out textValue);
|
|
||||||
|
|
||||||
if (isPlainTextValue)
|
|
||||||
{
|
|
||||||
// If it's a plain text value then we need to surround the value with quotes.
|
|
||||||
_writer
|
|
||||||
.WriteStartInstanceMethodInvocation(
|
|
||||||
ExecutionContextVariableName,
|
|
||||||
_tagHelperContext.ExecutionContextAddHtmlAttributeMethodName)
|
|
||||||
.WriteStringLiteral(attributeName)
|
|
||||||
.WriteParameterSeparator()
|
|
||||||
.WriteStartMethodInvocation(_tagHelperContext.MarkAsHtmlEncodedMethodName)
|
|
||||||
.WriteStringLiteral(textValue)
|
|
||||||
.WriteEndMethodInvocation(endLine: false)
|
|
||||||
.WriteEndMethodInvocation();
|
|
||||||
}
|
|
||||||
else if (IsDynamicAttributeValue(attributeValueChunk))
|
|
||||||
{
|
|
||||||
// Dynamic attribute value should be run through the conditional attribute removal system. It's
|
|
||||||
// unbound and contains C#.
|
|
||||||
|
|
||||||
// TagHelper attribute rendering is buffered by default. We do not want to write to the current
|
|
||||||
// writer.
|
|
||||||
var currentTargetWriter = _context.TargetWriterName;
|
|
||||||
var currentWriteAttributeMethodName = _context.Host.GeneratedClassContext.WriteAttributeValueMethodName;
|
|
||||||
_context.TargetWriterName = null;
|
|
||||||
|
|
||||||
Debug.Assert(attributeValueChunk is ParentChunk);
|
|
||||||
var children = ((ParentChunk)attributeValueChunk).Children;
|
|
||||||
var attributeCount = children.Count(c => c is DynamicCodeAttributeChunk || c is LiteralCodeAttributeChunk);
|
|
||||||
|
|
||||||
_writer
|
|
||||||
.WriteStartMethodInvocation(_tagHelperContext.BeginAddHtmlAttributeValuesMethodName)
|
|
||||||
.Write(ExecutionContextVariableName)
|
|
||||||
.WriteParameterSeparator()
|
|
||||||
.WriteStringLiteral(attributeName)
|
|
||||||
.WriteParameterSeparator()
|
|
||||||
.Write(attributeCount.ToString(CultureInfo.InvariantCulture))
|
|
||||||
.WriteEndMethodInvocation();
|
|
||||||
|
|
||||||
_attributeCodeVisitor.Accept(attributeValueChunk);
|
|
||||||
|
|
||||||
_writer.WriteMethodInvocation(
|
|
||||||
_tagHelperContext.EndAddHtmlAttributeValuesMethodName,
|
|
||||||
ExecutionContextVariableName);
|
|
||||||
|
|
||||||
_context.TargetWriterName = currentTargetWriter;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// HTML attributes are always strings. This attribute contains C# but is not dynamic. This occurs
|
|
||||||
// when the attribute is a data-* attribute.
|
|
||||||
|
|
||||||
// Attribute value is not plain text, must be buffered to determine its final value.
|
|
||||||
BuildBufferedWritingScope(attributeValueChunk, htmlEncodeValues: true);
|
|
||||||
|
|
||||||
_writer
|
|
||||||
.WriteStartInstanceMethodInvocation(
|
|
||||||
ExecutionContextVariableName,
|
|
||||||
_tagHelperContext.ExecutionContextAddHtmlAttributeMethodName)
|
|
||||||
.WriteStringLiteral(attributeName)
|
|
||||||
.WriteParameterSeparator()
|
|
||||||
.WriteStartMethodInvocation(_tagHelperContext.MarkAsHtmlEncodedMethodName);
|
|
||||||
|
|
||||||
RenderBufferedAttributeValueAccessor(_writer);
|
|
||||||
|
|
||||||
_writer
|
|
||||||
.WriteEndMethodInvocation(endLine: false)
|
|
||||||
.WriteEndMethodInvocation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RenderEndTagHelpersScope()
|
|
||||||
{
|
|
||||||
_writer.WriteStartAssignment(ExecutionContextVariableName)
|
|
||||||
.WriteInstanceMethodInvocation(ScopeManagerVariableName,
|
|
||||||
_tagHelperContext.ScopeManagerEndMethodName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RenderWriteTagHelperMethodCall(TagHelperChunk chunk)
|
|
||||||
{
|
|
||||||
_writer
|
|
||||||
.WriteStartInstrumentationContext(_context, chunk.Association, isLiteral: false)
|
|
||||||
.Write("await ");
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(_context.TargetWriterName))
|
|
||||||
{
|
|
||||||
_writer
|
|
||||||
.WriteStartMethodInvocation(_tagHelperContext.WriteTagHelperToAsyncMethodName)
|
|
||||||
.Write(_context.TargetWriterName)
|
|
||||||
.WriteParameterSeparator();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_writer.WriteStartMethodInvocation(_tagHelperContext.WriteTagHelperAsyncMethodName);
|
|
||||||
}
|
|
||||||
|
|
||||||
_writer
|
|
||||||
.Write(ExecutionContextVariableName)
|
|
||||||
.WriteEndMethodInvocation()
|
|
||||||
.WriteEndInstrumentationContext(_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RenderRunTagHelpers()
|
|
||||||
{
|
|
||||||
_writer.Write(ExecutionContextVariableName)
|
|
||||||
.Write(".")
|
|
||||||
.WriteStartAssignment(_tagHelperContext.ExecutionContextOutputPropertyName)
|
|
||||||
.Write("await ")
|
|
||||||
.WriteStartInstanceMethodInvocation(RunnerVariableName,
|
|
||||||
_tagHelperContext.RunnerRunAsyncMethodName);
|
|
||||||
|
|
||||||
_writer.Write(ExecutionContextVariableName)
|
|
||||||
.WriteEndMethodInvocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
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(
|
|
||||||
Chunk attributeValueChunk,
|
|
||||||
TagHelperAttributeDescriptor attributeDescriptor,
|
|
||||||
bool isPlainTextValue)
|
|
||||||
{
|
|
||||||
RenderAttributeValue(
|
|
||||||
attributeDescriptor,
|
|
||||||
valueRenderer: (writer) =>
|
|
||||||
{
|
|
||||||
var visitor =
|
|
||||||
new CSharpTagHelperAttributeValueVisitor(writer, _context, attributeDescriptor.TypeName);
|
|
||||||
visitor.Accept(attributeValueChunk);
|
|
||||||
},
|
|
||||||
complexValue: !isPlainTextValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RenderQuotedAttributeValue(string value, TagHelperAttributeDescriptor attributeDescriptor)
|
|
||||||
{
|
|
||||||
RenderAttributeValue(
|
|
||||||
attributeDescriptor,
|
|
||||||
valueRenderer: (writer) =>
|
|
||||||
{
|
|
||||||
writer.WriteStringLiteral(value);
|
|
||||||
},
|
|
||||||
complexValue: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render a buffered writing scope for the HTML attribute value.
|
|
||||||
private void BuildBufferedWritingScope(Chunk htmlAttributeChunk, bool htmlEncodeValues)
|
|
||||||
{
|
|
||||||
// We're building a writing scope around the provided chunks which captures everything written from the
|
|
||||||
// page. Therefore, we do not want to write to any other buffer since we're using the pages buffer to
|
|
||||||
// ensure we capture all content that's written, directly or indirectly.
|
|
||||||
var oldWriter = _context.TargetWriterName;
|
|
||||||
_context.TargetWriterName = null;
|
|
||||||
|
|
||||||
// Need to disable instrumentation inside of writing scopes, the instrumentation will not detect
|
|
||||||
// content written inside writing scopes.
|
|
||||||
var oldInstrumentation = _context.Host.EnableInstrumentation;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_context.Host.EnableInstrumentation = false;
|
|
||||||
|
|
||||||
// Scopes are a runtime feature.
|
|
||||||
if (!_designTimeMode)
|
|
||||||
{
|
|
||||||
_writer.WriteMethodInvocation(_tagHelperContext.StartTagHelperWritingScopeMethodName);
|
|
||||||
}
|
|
||||||
|
|
||||||
var visitor = htmlEncodeValues ? _bodyVisitor : _literalBodyVisitor;
|
|
||||||
visitor.Accept(htmlAttributeChunk);
|
|
||||||
|
|
||||||
// Scopes are a runtime feature.
|
|
||||||
if (!_designTimeMode)
|
|
||||||
{
|
|
||||||
_writer.WriteStartAssignment(StringValueBufferVariableName)
|
|
||||||
.WriteMethodInvocation(_tagHelperContext.EndTagHelperWritingScopeMethodName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// Reset instrumentation back to what it was, leaving the writing scope.
|
|
||||||
_context.Host.EnableInstrumentation = oldInstrumentation;
|
|
||||||
|
|
||||||
// Reset the writer/buffer back to what it was, leaving the writing scope.
|
|
||||||
_context.TargetWriterName = oldWriter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RenderAttributeValue(TagHelperAttributeDescriptor attributeDescriptor,
|
|
||||||
Action<CSharpCodeWriter> valueRenderer,
|
|
||||||
bool complexValue)
|
|
||||||
{
|
|
||||||
AttributeValueCodeRenderer.RenderAttributeValue(
|
|
||||||
attributeDescriptor,
|
|
||||||
_writer,
|
|
||||||
_context,
|
|
||||||
valueRenderer,
|
|
||||||
complexValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RenderBufferedAttributeValueAccessor(CSharpCodeWriter writer)
|
|
||||||
{
|
|
||||||
if (_designTimeMode)
|
|
||||||
{
|
|
||||||
// There is no value buffer in design time mode but we still want to write out a value. We write a
|
|
||||||
// value to ensure the tag helper's property type is string.
|
|
||||||
writer.Write("string.Empty");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
writer.WriteInstanceMethodInvocation(
|
|
||||||
StringValueBufferVariableName,
|
|
||||||
_tagHelperContext.TagHelperContentGetContentMethodName,
|
|
||||||
endLine: false,
|
|
||||||
parameters: new string[] { _tagHelperContext.HtmlEncoderPropertyName });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsDynamicAttributeValue(Chunk attributeValueChunk)
|
|
||||||
{
|
|
||||||
var parentChunk = attributeValueChunk as ParentChunk;
|
|
||||||
if (parentChunk != null)
|
|
||||||
{
|
|
||||||
return parentChunk.Children.Any(child => child is DynamicCodeAttributeChunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryGetPlainTextValue(Chunk chunk, out string plainText)
|
|
||||||
{
|
|
||||||
var parentChunk = chunk as ParentChunk;
|
|
||||||
|
|
||||||
plainText = null;
|
|
||||||
|
|
||||||
if (parentChunk == null || parentChunk.Children.Count != 1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var literalChildChunk = parentChunk.Children[0] as LiteralChunk;
|
|
||||||
|
|
||||||
if (literalChildChunk == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
plainText = literalChildChunk.Text;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A CSharpCodeVisitor which does not HTML encode values. Used when rendering bound string attribute values.
|
|
||||||
private class CSharpLiteralCodeVisitor : CSharpCodeVisitor
|
|
||||||
{
|
|
||||||
public CSharpLiteralCodeVisitor(
|
|
||||||
CSharpTagHelperCodeRenderer tagHelperRenderer,
|
|
||||||
CSharpCodeWriter writer,
|
|
||||||
CodeGeneratorContext context)
|
|
||||||
: base(writer, context)
|
|
||||||
{
|
|
||||||
// Ensure that no matter how this class is used, we don't create numerous CSharpTagHelperCodeRenderer
|
|
||||||
// instances.
|
|
||||||
TagHelperRenderer = tagHelperRenderer;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override string WriteMethodName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Context.Host.GeneratedClassContext.WriteLiteralMethodName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override string WriteToMethodName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Context.Host.GeneratedClassContext.WriteLiteralToMethodName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TagHelperAttributeCodeVisitor : CSharpCodeVisitor
|
|
||||||
{
|
|
||||||
public TagHelperAttributeCodeVisitor(
|
|
||||||
CSharpCodeWriter writer,
|
|
||||||
CodeGeneratorContext context)
|
|
||||||
: base(writer, context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override string WriteAttributeValueMethodName =>
|
|
||||||
Context.Host.GeneratedClassContext.GeneratedTagHelperContext.AddHtmlAttributeValueMethodName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
public abstract class CodeGenerator
|
|
||||||
{
|
|
||||||
private readonly CodeGeneratorContext _context;
|
|
||||||
|
|
||||||
public CodeGenerator(CodeGeneratorContext context)
|
|
||||||
{
|
|
||||||
_context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected CodeGeneratorContext Context
|
|
||||||
{
|
|
||||||
get { return _context; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract CodeGeneratorResult Generate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.AspNet.Razor.Chunks.Generators;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Context object with information used to generate a Razor page.
|
|
||||||
/// </summary>
|
|
||||||
public class CodeGeneratorContext : ChunkGeneratorContext
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of the <see cref="CodeGeneratorContext"/> object.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="generatorContext">A <see cref="ChunkGeneratorContext"/> to copy information from.</param>
|
|
||||||
/// <param name="errorSink">
|
|
||||||
/// The <see cref="ErrorSink"/> used to collect <see cref="RazorError"/>s encountered
|
|
||||||
/// when parsing the current Razor document.
|
|
||||||
/// </param>
|
|
||||||
public CodeGeneratorContext(ChunkGeneratorContext generatorContext, ErrorSink errorSink)
|
|
||||||
: base(generatorContext)
|
|
||||||
{
|
|
||||||
ErrorSink = errorSink;
|
|
||||||
ExpressionRenderingMode = ExpressionRenderingMode.WriteToOutput;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal for testing.
|
|
||||||
internal CodeGeneratorContext(
|
|
||||||
RazorEngineHost host,
|
|
||||||
string className,
|
|
||||||
string rootNamespace,
|
|
||||||
string sourceFile,
|
|
||||||
bool shouldGenerateLinePragmas,
|
|
||||||
ErrorSink errorSink)
|
|
||||||
: base(host, className, rootNamespace, sourceFile, shouldGenerateLinePragmas)
|
|
||||||
{
|
|
||||||
ErrorSink = errorSink;
|
|
||||||
ExpressionRenderingMode = ExpressionRenderingMode.WriteToOutput;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The current C# rendering mode.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// <see cref="ExpressionRenderingMode.WriteToOutput"/> forces C# generation to write
|
|
||||||
/// <see cref="Chunks.Chunk"/>s to the output page, i.e. WriteLiteral("Hello World").
|
|
||||||
/// <see cref="ExpressionRenderingMode.InjectCode"/> writes <see cref="Chunks.Chunk"/> values in their
|
|
||||||
/// rawest form, i.g. "Hello World".
|
|
||||||
/// </remarks>
|
|
||||||
public ExpressionRenderingMode ExpressionRenderingMode { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The C# writer to write <see cref="Chunks.Chunk"/> information to.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// If <see cref="TargetWriterName"/> is <c>null</c> values will be written using a default write method
|
|
||||||
/// i.e. WriteLiteral("Hello World").
|
|
||||||
/// If <see cref="TargetWriterName"/> is not <c>null</c> values will be written to the given
|
|
||||||
/// <see cref="TargetWriterName"/>, i.e. WriteLiteralTo(myWriter, "Hello World").
|
|
||||||
/// </remarks>
|
|
||||||
public string TargetWriterName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the <c>SHA1</c> based checksum for the file whose location is defined by
|
|
||||||
/// <see cref="ChunkGeneratorContext.SourceFile"/>.
|
|
||||||
/// </summary>
|
|
||||||
public string Checksum { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Used to aggregate <see cref="RazorError"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public ErrorSink ErrorSink { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
public class CodeGeneratorResult
|
|
||||||
{
|
|
||||||
public CodeGeneratorResult(string code, IList<LineMapping> designTimeLineMappings)
|
|
||||||
{
|
|
||||||
Code = code;
|
|
||||||
DesignTimeLineMappings = designTimeLineMappings;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Code { get; private set; }
|
|
||||||
public IList<LineMapping> DesignTimeLineMappings { get; private set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,216 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
public class CodeWriter : IDisposable
|
|
||||||
{
|
|
||||||
private static readonly char[] NewLineCharacters = new char[] { '\r', '\n' };
|
|
||||||
private readonly StringWriter _writer = new StringWriter();
|
|
||||||
private bool _newLine;
|
|
||||||
private string _cache = string.Empty;
|
|
||||||
private bool _dirty = false;
|
|
||||||
|
|
||||||
private int _absoluteIndex;
|
|
||||||
private int _currentLineIndex;
|
|
||||||
private int _currentLineCharacterIndex;
|
|
||||||
|
|
||||||
public string LastWrite { get; private set; }
|
|
||||||
|
|
||||||
public int CurrentIndent { get; private set; }
|
|
||||||
|
|
||||||
public string NewLine
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _writer.NewLine;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_writer.NewLine = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public CodeWriter ResetIndent()
|
|
||||||
{
|
|
||||||
return SetIndent(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CodeWriter IncreaseIndent(int size)
|
|
||||||
{
|
|
||||||
CurrentIndent += size;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CodeWriter DecreaseIndent(int size)
|
|
||||||
{
|
|
||||||
CurrentIndent -= size;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CodeWriter SetIndent(int size)
|
|
||||||
{
|
|
||||||
CurrentIndent = size;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CodeWriter Indent(int size)
|
|
||||||
{
|
|
||||||
if (_newLine)
|
|
||||||
{
|
|
||||||
_writer.Write(new string(' ', size));
|
|
||||||
Flush();
|
|
||||||
|
|
||||||
_currentLineCharacterIndex += size;
|
|
||||||
_absoluteIndex += size;
|
|
||||||
|
|
||||||
_dirty = true;
|
|
||||||
_newLine = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CodeWriter Write(string data)
|
|
||||||
{
|
|
||||||
Indent(CurrentIndent);
|
|
||||||
|
|
||||||
_writer.Write(data);
|
|
||||||
Flush();
|
|
||||||
|
|
||||||
LastWrite = data;
|
|
||||||
_dirty = true;
|
|
||||||
_newLine = false;
|
|
||||||
|
|
||||||
if (data == null || data.Length == 0)
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
_absoluteIndex += data.Length;
|
|
||||||
|
|
||||||
// The data string might contain a partial newline where the previously
|
|
||||||
// written string has part of the newline.
|
|
||||||
var i = 0;
|
|
||||||
int? trailingPartStart = null;
|
|
||||||
var builder = _writer.GetStringBuilder();
|
|
||||||
|
|
||||||
if (
|
|
||||||
// Check the last character of the previous write operation.
|
|
||||||
builder.Length - data.Length - 1 >= 0 &&
|
|
||||||
builder[builder.Length - data.Length - 1] == '\r' &&
|
|
||||||
|
|
||||||
// Check the first character of the current write operation.
|
|
||||||
builder[builder.Length - data.Length] == '\n')
|
|
||||||
{
|
|
||||||
// This is newline that's spread across two writes. Skip the first character of the
|
|
||||||
// current write operation.
|
|
||||||
//
|
|
||||||
// We don't need to increment our newline counter because we already did that when we
|
|
||||||
// saw the \r.
|
|
||||||
i += 1;
|
|
||||||
trailingPartStart = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate the string, stopping at each occurrence of a newline character. This lets us count the
|
|
||||||
// newline occurrences and keep the index of the last one.
|
|
||||||
while ((i = data.IndexOfAny(NewLineCharacters, i)) >= 0)
|
|
||||||
{
|
|
||||||
// Newline found.
|
|
||||||
_currentLineIndex++;
|
|
||||||
_currentLineCharacterIndex = 0;
|
|
||||||
|
|
||||||
i++;
|
|
||||||
|
|
||||||
// We might have stopped at a \r, so check if it's followed by \n and then advance the index to
|
|
||||||
// start the next search after it.
|
|
||||||
if (data.Length > i &&
|
|
||||||
data[i - 1] == '\r' &&
|
|
||||||
data[i] == '\n')
|
|
||||||
{
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The 'suffix' of the current line starts after this newline token.
|
|
||||||
trailingPartStart = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trailingPartStart == null)
|
|
||||||
{
|
|
||||||
// No newlines, just add the length of the data buffer
|
|
||||||
_currentLineCharacterIndex += data.Length;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Newlines found, add the trailing part of 'data'
|
|
||||||
_currentLineCharacterIndex += (data.Length - trailingPartStart.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CodeWriter WriteLine()
|
|
||||||
{
|
|
||||||
LastWrite = _writer.NewLine;
|
|
||||||
|
|
||||||
_writer.WriteLine();
|
|
||||||
Flush();
|
|
||||||
|
|
||||||
_currentLineIndex++;
|
|
||||||
_currentLineCharacterIndex = 0;
|
|
||||||
_absoluteIndex += _writer.NewLine.Length;
|
|
||||||
|
|
||||||
_dirty = true;
|
|
||||||
_newLine = true;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CodeWriter WriteLine(string data)
|
|
||||||
{
|
|
||||||
return Write(data).WriteLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
public CodeWriter Flush()
|
|
||||||
{
|
|
||||||
_writer.Flush();
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GenerateCode()
|
|
||||||
{
|
|
||||||
if (_dirty)
|
|
||||||
{
|
|
||||||
_cache = _writer.ToString();
|
|
||||||
_dirty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SourceLocation GetCurrentSourceLocation()
|
|
||||||
{
|
|
||||||
return new SourceLocation(_absoluteIndex, _currentLineIndex, _currentLineCharacterIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
_writer.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(disposing: true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
public enum ExpressionRenderingMode
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates that expressions should be written to the output stream
|
|
||||||
/// </summary>
|
|
||||||
/// <example>
|
|
||||||
/// If @foo is rendered with WriteToOutput, the code generator would output the following code:
|
|
||||||
///
|
|
||||||
/// Write(foo);
|
|
||||||
/// </example>
|
|
||||||
WriteToOutput,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates that expressions should simply be placed as-is in the code, and the context in which
|
|
||||||
/// the code exists will be used to render it
|
|
||||||
/// </summary>
|
|
||||||
/// <example>
|
|
||||||
/// If @foo is rendered with InjectCode, the code generator would output the following code:
|
|
||||||
///
|
|
||||||
/// foo
|
|
||||||
/// </example>
|
|
||||||
InjectCode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,219 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.Extensions.Internal;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
public struct GeneratedClassContext
|
|
||||||
{
|
|
||||||
public static readonly string DefaultWriteMethodName = "Write";
|
|
||||||
public static readonly string DefaultWriteLiteralMethodName = "WriteLiteral";
|
|
||||||
public static readonly string DefaultExecuteMethodName = "ExecuteAsync";
|
|
||||||
public static readonly string DefaultBeginWriteAttributeMethodName = "BeginWriteAttribute";
|
|
||||||
public static readonly string DefaultBeginWriteAttributeToMethodName = "BeginWriteAttributeTo";
|
|
||||||
public static readonly string DefaultEndWriteAttributeMethodName = "EndWriteAttribute";
|
|
||||||
public static readonly string DefaultEndWriteAttributeToMethodName = "EndWriteAttributeTo";
|
|
||||||
public static readonly string DefaultWriteAttributeValueMethodName = "WriteAttributeValue";
|
|
||||||
public static readonly string DefaultWriteAttributeValueToMethodName = "WriteAttributeValueTo";
|
|
||||||
|
|
||||||
public static readonly GeneratedClassContext Default =
|
|
||||||
new GeneratedClassContext(
|
|
||||||
DefaultExecuteMethodName,
|
|
||||||
DefaultWriteMethodName,
|
|
||||||
DefaultWriteLiteralMethodName,
|
|
||||||
new GeneratedTagHelperContext());
|
|
||||||
|
|
||||||
public GeneratedClassContext(
|
|
||||||
string executeMethodName,
|
|
||||||
string writeMethodName,
|
|
||||||
string writeLiteralMethodName,
|
|
||||||
GeneratedTagHelperContext generatedTagHelperContext)
|
|
||||||
: this()
|
|
||||||
{
|
|
||||||
if (generatedTagHelperContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(generatedTagHelperContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(executeMethodName))
|
|
||||||
{
|
|
||||||
throw new ArgumentException(
|
|
||||||
CommonResources.Argument_Cannot_Be_Null_Or_Empty,
|
|
||||||
nameof(executeMethodName));
|
|
||||||
}
|
|
||||||
if (string.IsNullOrEmpty(writeMethodName))
|
|
||||||
{
|
|
||||||
throw new ArgumentException(
|
|
||||||
CommonResources.Argument_Cannot_Be_Null_Or_Empty,
|
|
||||||
nameof(writeMethodName));
|
|
||||||
}
|
|
||||||
if (string.IsNullOrEmpty(writeLiteralMethodName))
|
|
||||||
{
|
|
||||||
throw new ArgumentException(
|
|
||||||
CommonResources.Argument_Cannot_Be_Null_Or_Empty,
|
|
||||||
nameof(writeLiteralMethodName));
|
|
||||||
}
|
|
||||||
|
|
||||||
GeneratedTagHelperContext = generatedTagHelperContext;
|
|
||||||
|
|
||||||
WriteMethodName = writeMethodName;
|
|
||||||
WriteLiteralMethodName = writeLiteralMethodName;
|
|
||||||
ExecuteMethodName = executeMethodName;
|
|
||||||
|
|
||||||
WriteToMethodName = null;
|
|
||||||
WriteLiteralToMethodName = null;
|
|
||||||
TemplateTypeName = null;
|
|
||||||
DefineSectionMethodName = null;
|
|
||||||
|
|
||||||
BeginWriteAttributeMethodName = DefaultBeginWriteAttributeMethodName;
|
|
||||||
BeginWriteAttributeToMethodName = DefaultBeginWriteAttributeToMethodName;
|
|
||||||
EndWriteAttributeMethodName = DefaultEndWriteAttributeMethodName;
|
|
||||||
EndWriteAttributeToMethodName = DefaultEndWriteAttributeToMethodName;
|
|
||||||
WriteAttributeValueMethodName = DefaultWriteAttributeValueMethodName;
|
|
||||||
WriteAttributeValueToMethodName = DefaultWriteAttributeValueToMethodName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GeneratedClassContext(
|
|
||||||
string executeMethodName,
|
|
||||||
string writeMethodName,
|
|
||||||
string writeLiteralMethodName,
|
|
||||||
string writeToMethodName,
|
|
||||||
string writeLiteralToMethodName,
|
|
||||||
string templateTypeName,
|
|
||||||
GeneratedTagHelperContext generatedTagHelperContext)
|
|
||||||
: this(executeMethodName,
|
|
||||||
writeMethodName,
|
|
||||||
writeLiteralMethodName,
|
|
||||||
generatedTagHelperContext)
|
|
||||||
{
|
|
||||||
WriteToMethodName = writeToMethodName;
|
|
||||||
WriteLiteralToMethodName = writeLiteralToMethodName;
|
|
||||||
TemplateTypeName = templateTypeName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GeneratedClassContext(
|
|
||||||
string executeMethodName,
|
|
||||||
string writeMethodName,
|
|
||||||
string writeLiteralMethodName,
|
|
||||||
string writeToMethodName,
|
|
||||||
string writeLiteralToMethodName,
|
|
||||||
string templateTypeName,
|
|
||||||
string defineSectionMethodName,
|
|
||||||
GeneratedTagHelperContext generatedTagHelperContext)
|
|
||||||
: this(executeMethodName,
|
|
||||||
writeMethodName,
|
|
||||||
writeLiteralMethodName,
|
|
||||||
writeToMethodName,
|
|
||||||
writeLiteralToMethodName,
|
|
||||||
templateTypeName,
|
|
||||||
generatedTagHelperContext)
|
|
||||||
{
|
|
||||||
DefineSectionMethodName = defineSectionMethodName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GeneratedClassContext(
|
|
||||||
string executeMethodName,
|
|
||||||
string writeMethodName,
|
|
||||||
string writeLiteralMethodName,
|
|
||||||
string writeToMethodName,
|
|
||||||
string writeLiteralToMethodName,
|
|
||||||
string templateTypeName,
|
|
||||||
string defineSectionMethodName,
|
|
||||||
string beginContextMethodName,
|
|
||||||
string endContextMethodName,
|
|
||||||
GeneratedTagHelperContext generatedTagHelperContext)
|
|
||||||
: this(executeMethodName,
|
|
||||||
writeMethodName,
|
|
||||||
writeLiteralMethodName,
|
|
||||||
writeToMethodName,
|
|
||||||
writeLiteralToMethodName,
|
|
||||||
templateTypeName,
|
|
||||||
defineSectionMethodName,
|
|
||||||
generatedTagHelperContext)
|
|
||||||
{
|
|
||||||
BeginContextMethodName = beginContextMethodName;
|
|
||||||
EndContextMethodName = endContextMethodName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required Items
|
|
||||||
public string WriteMethodName { get; }
|
|
||||||
public string WriteLiteralMethodName { get; }
|
|
||||||
public string WriteToMethodName { get; }
|
|
||||||
public string WriteLiteralToMethodName { get; }
|
|
||||||
public string ExecuteMethodName { get; }
|
|
||||||
public GeneratedTagHelperContext GeneratedTagHelperContext { get; }
|
|
||||||
|
|
||||||
// Optional Items
|
|
||||||
public string BeginContextMethodName { get; set; }
|
|
||||||
public string EndContextMethodName { get; set; }
|
|
||||||
public string DefineSectionMethodName { get; set; }
|
|
||||||
public string TemplateTypeName { get; set; }
|
|
||||||
|
|
||||||
public string BeginWriteAttributeMethodName { get; set; }
|
|
||||||
public string BeginWriteAttributeToMethodName { get; set; }
|
|
||||||
public string EndWriteAttributeMethodName { get; set; }
|
|
||||||
public string EndWriteAttributeToMethodName { get; set; }
|
|
||||||
public string WriteAttributeValueMethodName { get; set; }
|
|
||||||
public string WriteAttributeValueToMethodName { get; set; }
|
|
||||||
|
|
||||||
public bool AllowSections
|
|
||||||
{
|
|
||||||
get { return !string.IsNullOrEmpty(DefineSectionMethodName); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AllowTemplates
|
|
||||||
{
|
|
||||||
get { return !string.IsNullOrEmpty(TemplateTypeName); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SupportsInstrumentation
|
|
||||||
{
|
|
||||||
get { return !string.IsNullOrEmpty(BeginContextMethodName) && !string.IsNullOrEmpty(EndContextMethodName); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
if (!(obj is GeneratedClassContext))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var other = (GeneratedClassContext)obj;
|
|
||||||
return string.Equals(DefineSectionMethodName, other.DefineSectionMethodName, StringComparison.Ordinal) &&
|
|
||||||
string.Equals(WriteMethodName, other.WriteMethodName, StringComparison.Ordinal) &&
|
|
||||||
string.Equals(WriteLiteralMethodName, other.WriteLiteralMethodName, StringComparison.Ordinal) &&
|
|
||||||
string.Equals(WriteToMethodName, other.WriteToMethodName, StringComparison.Ordinal) &&
|
|
||||||
string.Equals(WriteLiteralToMethodName, other.WriteLiteralToMethodName, StringComparison.Ordinal) &&
|
|
||||||
string.Equals(ExecuteMethodName, other.ExecuteMethodName, StringComparison.Ordinal) &&
|
|
||||||
string.Equals(TemplateTypeName, other.TemplateTypeName, StringComparison.Ordinal) &&
|
|
||||||
string.Equals(BeginContextMethodName, other.BeginContextMethodName, StringComparison.Ordinal) &&
|
|
||||||
string.Equals(EndContextMethodName, other.EndContextMethodName, StringComparison.Ordinal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
// Hash code should include only immutable properties.
|
|
||||||
var hashCodeCombiner = HashCodeCombiner.Start();
|
|
||||||
|
|
||||||
hashCodeCombiner.Add(WriteMethodName, StringComparer.Ordinal);
|
|
||||||
hashCodeCombiner.Add(WriteLiteralMethodName, StringComparer.Ordinal);
|
|
||||||
hashCodeCombiner.Add(WriteToMethodName, StringComparer.Ordinal);
|
|
||||||
hashCodeCombiner.Add(WriteLiteralToMethodName, StringComparer.Ordinal);
|
|
||||||
hashCodeCombiner.Add(ExecuteMethodName, StringComparer.Ordinal);
|
|
||||||
|
|
||||||
return hashCodeCombiner;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(GeneratedClassContext left, GeneratedClassContext right)
|
|
||||||
{
|
|
||||||
return left.Equals(right);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator !=(GeneratedClassContext left, GeneratedClassContext right)
|
|
||||||
{
|
|
||||||
return !left.Equals(right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,209 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Contains necessary information for the tag helper code generation process.
|
|
||||||
/// </summary>
|
|
||||||
public class GeneratedTagHelperContext
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new instance of the <see cref="GeneratedTagHelperContext"/> with default values.
|
|
||||||
/// </summary>
|
|
||||||
public GeneratedTagHelperContext()
|
|
||||||
{
|
|
||||||
BeginAddHtmlAttributeValuesMethodName = "BeginAddHtmlAttributeValues";
|
|
||||||
EndAddHtmlAttributeValuesMethodName = "EndAddHtmlAttributeValues";
|
|
||||||
AddHtmlAttributeValueMethodName = "AddHtmlAttributeValue";
|
|
||||||
CreateTagHelperMethodName = "CreateTagHelper";
|
|
||||||
RunnerRunAsyncMethodName = "RunAsync";
|
|
||||||
ScopeManagerBeginMethodName = "Begin";
|
|
||||||
ScopeManagerEndMethodName = "End";
|
|
||||||
ExecutionContextAddMethodName = "Add";
|
|
||||||
ExecutionContextAddTagHelperAttributeMethodName = "AddTagHelperAttribute";
|
|
||||||
ExecutionContextAddMinimizedHtmlAttributeMethodName = "AddMinimizedHtmlAttribute";
|
|
||||||
ExecutionContextAddHtmlAttributeMethodName = "AddHtmlAttribute";
|
|
||||||
ExecutionContextOutputPropertyName = "Output";
|
|
||||||
FormatInvalidIndexerAssignmentMethodName = "FormatInvalidIndexerAssignment";
|
|
||||||
MarkAsHtmlEncodedMethodName = "Html.Raw";
|
|
||||||
StartTagHelperWritingScopeMethodName = "StartTagHelperWritingScope";
|
|
||||||
EndTagHelperWritingScopeMethodName = "EndTagHelperWritingScope";
|
|
||||||
RunnerTypeName = "TagHelperRunner";
|
|
||||||
ScopeManagerTypeName = "TagHelperScopeManager";
|
|
||||||
ExecutionContextTypeName = "TagHelperExecutionContext";
|
|
||||||
TagHelperContentTypeName = "TagHelperContent";
|
|
||||||
WriteTagHelperAsyncMethodName = "WriteTagHelperAsync";
|
|
||||||
WriteTagHelperToAsyncMethodName = "WriteTagHelperToAsync";
|
|
||||||
TagHelperContentGetContentMethodName = "GetContent";
|
|
||||||
HtmlEncoderPropertyName = "HtmlEncoder";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the method used to begin the addition of unbound, complex tag helper attributes to
|
|
||||||
/// TagHelperExecutionContexts.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Method signature should be
|
|
||||||
/// <code>
|
|
||||||
/// public void BeginAddHtmlAttributeValues(
|
|
||||||
/// TagHelperExecutionContext executionContext,
|
|
||||||
/// string attributeName)
|
|
||||||
/// </code>
|
|
||||||
/// </remarks>
|
|
||||||
public string BeginAddHtmlAttributeValuesMethodName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Method name used to end addition of unbound, complex tag helper attributes to TagHelperExecutionContexts.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Method signature should be
|
|
||||||
/// <code>
|
|
||||||
/// public void EndAddHtmlAttributeValues(
|
|
||||||
/// TagHelperExecutionContext executionContext)
|
|
||||||
/// </code>
|
|
||||||
/// </remarks>
|
|
||||||
public string EndAddHtmlAttributeValuesMethodName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Method name used to add individual components of an unbound, complex tag helper attribute to
|
|
||||||
/// TagHelperExecutionContexts.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Method signature:
|
|
||||||
/// <code>
|
|
||||||
/// public void AddHtmlAttributeValues(
|
|
||||||
/// string prefix,
|
|
||||||
/// int prefixOffset,
|
|
||||||
/// string value,
|
|
||||||
/// int valueOffset,
|
|
||||||
/// int valueLength,
|
|
||||||
/// bool isLiteral)
|
|
||||||
/// </code>
|
|
||||||
/// </remarks>
|
|
||||||
public string AddHtmlAttributeValueMethodName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the method used to create a tag helper.
|
|
||||||
/// </summary>
|
|
||||||
public string CreateTagHelperMethodName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the <see cref="RunnerTypeName"/> method used to run tag helpers.
|
|
||||||
/// </summary>
|
|
||||||
public string RunnerRunAsyncMethodName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the <see cref="ExecutionContextTypeName"/> method used to start a scope.
|
|
||||||
/// </summary>
|
|
||||||
public string ScopeManagerBeginMethodName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the <see cref="ExecutionContextTypeName"/> method used to end a scope.
|
|
||||||
/// </summary>
|
|
||||||
public string ScopeManagerEndMethodName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the <see cref="ExecutionContextTypeName"/> method used to add tag helper attributes.
|
|
||||||
/// </summary>
|
|
||||||
public string ExecutionContextAddTagHelperAttributeMethodName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the <see cref="ExecutionContextTypeName"/> method used to add minimized HTML attributes.
|
|
||||||
/// </summary>
|
|
||||||
public string ExecutionContextAddMinimizedHtmlAttributeMethodName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the <see cref="ExecutionContextTypeName"/> method used to add HTML attributes.
|
|
||||||
/// </summary>
|
|
||||||
public string ExecutionContextAddHtmlAttributeMethodName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the <see cref="ExecutionContextTypeName"/> method used to add tag helpers.
|
|
||||||
/// </summary>
|
|
||||||
public string ExecutionContextAddMethodName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The property accessor for the tag helper's output.
|
|
||||||
/// </summary>
|
|
||||||
public string ExecutionContextOutputPropertyName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the method used to format an error message about using an indexer when the tag helper property
|
|
||||||
/// is <c>null</c>.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Method signature should be
|
|
||||||
/// <code>
|
|
||||||
/// public string FormatInvalidIndexerAssignment(
|
|
||||||
/// string attributeName, // Name of the HTML attribute associated with the indexer.
|
|
||||||
/// string tagHelperTypeName, // Full name of the tag helper type.
|
|
||||||
/// string propertyName) // Dictionary property in the tag helper.
|
|
||||||
/// </code>
|
|
||||||
/// </remarks>
|
|
||||||
public string FormatInvalidIndexerAssignmentMethodName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the method used to wrap a <see cref="string"/> value and mark it as HTML-encoded.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>Used together with <see cref="ExecutionContextAddHtmlAttributeMethodName"/>.</remarks>
|
|
||||||
public string MarkAsHtmlEncodedMethodName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the method used to start a new writing scope.
|
|
||||||
/// </summary>
|
|
||||||
public string StartTagHelperWritingScopeMethodName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the method used to end a writing scope.
|
|
||||||
/// </summary>
|
|
||||||
public string EndTagHelperWritingScopeMethodName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the type used to run tag helpers.
|
|
||||||
/// </summary>
|
|
||||||
public string RunnerTypeName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the type used to create scoped <see cref="ExecutionContextTypeName"/> instances.
|
|
||||||
/// </summary>
|
|
||||||
public string ScopeManagerTypeName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the type describing a specific tag helper scope.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Contains information about in-scope tag helpers, HTML attributes, and the tag helpers' output.
|
|
||||||
/// </remarks>
|
|
||||||
public string ExecutionContextTypeName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the type containing tag helper content.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Contains the data returned by EndTagHelperWriteScope().
|
|
||||||
/// </remarks>
|
|
||||||
public string TagHelperContentTypeName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the method used to write <see cref="ExecutionContextTypeName"/>.
|
|
||||||
/// </summary>
|
|
||||||
public string WriteTagHelperAsyncMethodName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the method used to write <see cref="ExecutionContextTypeName"/> to a specified
|
|
||||||
/// <see cref="System.IO.TextWriter"/>.
|
|
||||||
/// </summary>
|
|
||||||
public string WriteTagHelperToAsyncMethodName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the property containing the <c>IHtmlEncoder</c>.
|
|
||||||
/// </summary>
|
|
||||||
public string HtmlEncoderPropertyName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the method used to convert a <c>TagHelperContent</c> into a <see cref="string"/>.
|
|
||||||
/// </summary>
|
|
||||||
public string TagHelperContentGetContentMethodName { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,111 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Microsoft.AspNet.Razor.Chunks;
|
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
|
||||||
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The results of parsing and generating code for a Razor document.
|
|
||||||
/// </summary>
|
|
||||||
public class GeneratorResults : ParserResults
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new <see cref="GeneratorResults"/> instance.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="parserResults">The results of parsing a document.</param>
|
|
||||||
/// <param name="codeGeneratorResult">The results of generating code for the document.</param>
|
|
||||||
/// <param name="chunkTree">A <see cref="ChunkTree"/> for the document.</param>
|
|
||||||
public GeneratorResults(ParserResults parserResults,
|
|
||||||
CodeGeneratorResult codeGeneratorResult,
|
|
||||||
ChunkTree chunkTree)
|
|
||||||
: this(parserResults.Document,
|
|
||||||
parserResults.TagHelperDescriptors,
|
|
||||||
parserResults.ErrorSink,
|
|
||||||
codeGeneratorResult,
|
|
||||||
chunkTree)
|
|
||||||
{
|
|
||||||
if (parserResults == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(parserResults));
|
|
||||||
}
|
|
||||||
if (codeGeneratorResult == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(codeGeneratorResult));
|
|
||||||
}
|
|
||||||
if (chunkTree == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(chunkTree));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a new <see cref="GeneratorResults"/> instance.
|
|
||||||
/// </summary>
|
|
||||||
/// <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="ErrorSink"/> used to collect <see cref="RazorError"/>s encountered when parsing the
|
|
||||||
/// current Razor document.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="codeGeneratorResult">The results of generating code for the document.</param>
|
|
||||||
/// <param name="chunkTree">A <see cref="ChunkTree"/> for the document.</param>
|
|
||||||
public GeneratorResults(Block document,
|
|
||||||
IEnumerable<TagHelperDescriptor> tagHelperDescriptors,
|
|
||||||
ErrorSink errorSink,
|
|
||||||
CodeGeneratorResult codeGeneratorResult,
|
|
||||||
ChunkTree chunkTree)
|
|
||||||
: base(document, tagHelperDescriptors, errorSink)
|
|
||||||
{
|
|
||||||
if (document == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(document));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tagHelperDescriptors == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(tagHelperDescriptors));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errorSink == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(errorSink));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (codeGeneratorResult == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(codeGeneratorResult));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chunkTree == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(chunkTree));
|
|
||||||
}
|
|
||||||
|
|
||||||
GeneratedCode = codeGeneratorResult.Code;
|
|
||||||
DesignTimeLineMappings = codeGeneratorResult.DesignTimeLineMappings;
|
|
||||||
ChunkTree = chunkTree;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The generated code for the document.
|
|
||||||
/// </summary>
|
|
||||||
public string GeneratedCode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <see cref="LineMapping"/>s used to project code from a file during design time.
|
|
||||||
/// </summary>
|
|
||||||
public IList<LineMapping> DesignTimeLineMappings { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A <see cref="Chunks.ChunkTree"/> for the document.
|
|
||||||
/// </summary>
|
|
||||||
public ChunkTree ChunkTree { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Globalization;
|
|
||||||
using Microsoft.Extensions.Internal;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
public class LineMapping
|
|
||||||
{
|
|
||||||
public LineMapping(MappingLocation documentLocation, MappingLocation generatedLocation)
|
|
||||||
{
|
|
||||||
DocumentLocation = documentLocation;
|
|
||||||
GeneratedLocation = generatedLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MappingLocation DocumentLocation { get; }
|
|
||||||
|
|
||||||
public MappingLocation GeneratedLocation { get; }
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
var other = obj as LineMapping;
|
|
||||||
if (ReferenceEquals(other, null))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return DocumentLocation.Equals(other.DocumentLocation) &&
|
|
||||||
GeneratedLocation.Equals(other.GeneratedLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
var hashCodeCombiner = HashCodeCombiner.Start();
|
|
||||||
hashCodeCombiner.Add(DocumentLocation);
|
|
||||||
hashCodeCombiner.Add(GeneratedLocation);
|
|
||||||
|
|
||||||
return hashCodeCombiner;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(LineMapping left, LineMapping right)
|
|
||||||
{
|
|
||||||
if (ReferenceEquals(left, right))
|
|
||||||
{
|
|
||||||
// Exact equality e.g. both objects are null.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ReferenceEquals(left, null))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return left.Equals(right);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator !=(LineMapping left, LineMapping right)
|
|
||||||
{
|
|
||||||
if (ReferenceEquals(left, right))
|
|
||||||
{
|
|
||||||
// Exact equality e.g. both objects are null.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ReferenceEquals(left, null))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !left.Equals(right);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentUICulture, "{0} -> {1}", DocumentLocation, GeneratedLocation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
public class LineMappingManager
|
|
||||||
{
|
|
||||||
public LineMappingManager()
|
|
||||||
{
|
|
||||||
Mappings = new List<LineMapping>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<LineMapping> Mappings { get; }
|
|
||||||
|
|
||||||
public void AddMapping(MappingLocation documentLocation, MappingLocation generatedLocation)
|
|
||||||
{
|
|
||||||
Mappings.Add(new LineMapping(documentLocation, generatedLocation));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Globalization;
|
|
||||||
using Microsoft.Extensions.Internal;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
|
||||||
{
|
|
||||||
public class MappingLocation
|
|
||||||
{
|
|
||||||
public MappingLocation()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public MappingLocation(SourceLocation location, int contentLength)
|
|
||||||
{
|
|
||||||
ContentLength = contentLength;
|
|
||||||
AbsoluteIndex = location.AbsoluteIndex;
|
|
||||||
LineIndex = location.LineIndex;
|
|
||||||
CharacterIndex = location.CharacterIndex;
|
|
||||||
FilePath = location.FilePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ContentLength { get; }
|
|
||||||
|
|
||||||
public int AbsoluteIndex { get; }
|
|
||||||
|
|
||||||
public int LineIndex { get; }
|
|
||||||
|
|
||||||
public int CharacterIndex { get; }
|
|
||||||
|
|
||||||
public string FilePath { get; }
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
var other = obj as MappingLocation;
|
|
||||||
if (ReferenceEquals(other, null))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Equals(FilePath, other.FilePath, StringComparison.Ordinal) &&
|
|
||||||
AbsoluteIndex == other.AbsoluteIndex &&
|
|
||||||
ContentLength == other.ContentLength &&
|
|
||||||
LineIndex == other.LineIndex &&
|
|
||||||
CharacterIndex == other.CharacterIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
var hashCodeCombiner = HashCodeCombiner.Start();
|
|
||||||
hashCodeCombiner.Add(FilePath, StringComparer.Ordinal);
|
|
||||||
hashCodeCombiner.Add(AbsoluteIndex);
|
|
||||||
hashCodeCombiner.Add(ContentLength);
|
|
||||||
hashCodeCombiner.Add(LineIndex);
|
|
||||||
hashCodeCombiner.Add(CharacterIndex);
|
|
||||||
|
|
||||||
return hashCodeCombiner;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return string.Format(
|
|
||||||
CultureInfo.CurrentCulture, "({0}:{1},{2} [{3}] {4})",
|
|
||||||
AbsoluteIndex,
|
|
||||||
LineIndex,
|
|
||||||
CharacterIndex,
|
|
||||||
ContentLength,
|
|
||||||
FilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(MappingLocation left, MappingLocation right)
|
|
||||||
{
|
|
||||||
if (ReferenceEquals(left, right))
|
|
||||||
{
|
|
||||||
// Exact equality e.g. both objects are null.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ReferenceEquals(left, null))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return left.Equals(right);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator !=(MappingLocation left, MappingLocation right)
|
|
||||||
{
|
|
||||||
if (ReferenceEquals(left, right))
|
|
||||||
{
|
|
||||||
// Exact equality e.g. both objects are null.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ReferenceEquals(left, null))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !left.Equals(right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue