Skip to content

Instantly share code, notes, and snippets.

@rynowak
Created February 14, 2017 21:01
Show Gist options
  • Save rynowak/5f26e0922a5579853a041b2a26dd151f to your computer and use it in GitHub Desktop.
Save rynowak/5f26e0922a5579853a041b2a26dd151f to your computer and use it in GitHub Desktop.
TagHelperDescriptor
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.VisualStudio.LanguageServices.Razor.New
{
public abstract class TagHelperDescriptor
{
private IEnumerable<RazorDiagnostic> _allDiagnostics;
protected TagHelperDescriptor(string kind)
{
Kind = kind;
}
public string Kind { get; }
public IEnumerable<TagMatchingRule> TagMatchingRules { get; protected set; }
public string AssemblyName { get; protected set; }
public IEnumerable<BoundAttributeDescriptor> BoundAttributes { get; protected set; }
public IEnumerable<string> AllowedChildTags { get; protected set; }
public IReadOnlyDictionary<string, string> Metadata { get; protected set; }
public string DisplayName { get; protected set; }
public string Name { get; protected set; }
public string Documentation { get; protected set; }
public string TagOutputHint { get; protected set; }
public IEnumerable<RazorDiagnostic> Diagnostics { get; protected set; }
public bool HasAnyErrors
{
get
{
var allDiagnostics = GetAllDiagnostics();
var anyErrors = allDiagnostics.Any(diagnostic => diagnostic.Severity == RazorDiagnosticSeverity.Error);
return anyErrors;
}
}
public IEnumerable<RazorDiagnostic> GetAllDiagnostics()
{
if (_allDiagnostics == null)
{
var attributeErrors = BoundAttributes.SelectMany(attribute => attribute.Diagnostics);
var ruleErrors = TagMatchingRules.SelectMany(rule => rule.GetAllDiagnostics());
var combinedDiagnostics = attributeErrors.Concat(ruleErrors);
_allDiagnostics = combinedDiagnostics.ToArray();
}
return _allDiagnostics;
}
}
public abstract class TagMatchingRule
{
private IEnumerable<RazorDiagnostic> _allDiagnostics;
public string TagName { get; protected set; }
public IEnumerable<RequiredAttributeDescriptor> Attributes { get; protected set; }
public string ParentTag { get; protected set; }
public TagStructure TagStructure { get; protected set; }
public IEnumerable<RazorDiagnostic> Diagnostics { get; protected set; }
public bool HasAnyErrors
{
get
{
var allDiagnostics = GetAllDiagnostics();
var anyErrors = allDiagnostics.Any(diagnostic => diagnostic.Severity == RazorDiagnosticSeverity.Error);
return anyErrors;
}
}
public IEnumerable<RazorDiagnostic> GetAllDiagnostics()
{
if (_allDiagnostics == null)
{
var requiredAttributeDiagnostics = Attributes.SelectMany(attribute => attribute.Diagnostics);
var combinedDiagnostics = Diagnostics.Concat(requiredAttributeDiagnostics);
_allDiagnostics = combinedDiagnostics.ToArray();
}
return _allDiagnostics;
}
}
public abstract class BoundAttributeDescriptor
{
protected BoundAttributeDescriptor(string kind)
{
Kind = kind;
}
public string Kind { get; }
public bool IsKeyValueStringProperty { get; protected set; }
public bool IsEnum { get; protected set; }
public bool IsStringProperty { get; protected set; }
public string Name { get; protected set; }
public string TypeName { get; protected set; }
public string KeyValueTypeName { get; protected set; }
public IReadOnlyDictionary<string, string> Metadata { get; protected set; }
public string Documentation { get; protected set; }
public string DisplayName { get; protected set; }
public IEnumerable<RazorDiagnostic> Diagnostics { get; protected set; }
public bool HasAnyErrors
{
get
{
var anyErrors = Diagnostics.Any(diagnostic => diagnostic.Severity == RazorDiagnosticSeverity.Error);
return anyErrors;
}
}
}
public abstract class RequiredAttributeDescriptor
{
public string Name { get; protected set; }
public NameComparisonMode NameComparison { get; protected set; }
public string Value { get; protected set; }
public ValueComparisonMode ValueComparison { get; protected set; }
public IEnumerable<RazorDiagnostic> Diagnostics { get; protected set; }
public bool HasAnyErrors
{
get
{
var anyErrors = Diagnostics.Any(diagnostic => diagnostic.Severity == RazorDiagnosticSeverity.Error);
return anyErrors;
}
}
/// <summary>
/// Determines if the current <see cref="RequiredAttributeDescriptor"/> matches the given
/// <paramref name="attributeName"/> and <paramref name="attributeValue"/>.
/// </summary>
/// <param name="attributeName">An HTML attribute name.</param>
/// <param name="attributeValue">An HTML attribute value.</param>
/// <returns><c>true</c> if the current <see cref="RequiredAttributeDescriptor"/> matches
/// <paramref name="attributeName"/> and <paramref name="attributeValue"/>; <c>false</c> otherwise.</returns>
public bool IsMatch(string attributeName, string attributeValue)
{
var nameMatches = false;
if (NameComparison == NameComparisonMode.FullMatch)
{
nameMatches = string.Equals(Name, attributeName, StringComparison.OrdinalIgnoreCase);
}
else if (NameComparison == NameComparisonMode.PrefixMatch)
{
// attributeName cannot equal the Name if comparing as a PrefixMatch.
nameMatches = attributeName.Length != Name.Length &&
attributeName.StartsWith(Name, StringComparison.OrdinalIgnoreCase);
}
else
{
Debug.Assert(false, "Unknown name comparison.");
}
if (!nameMatches)
{
return false;
}
switch (ValueComparison)
{
case ValueComparisonMode.None:
return true;
case ValueComparisonMode.PrefixMatch: // Value starts with
return attributeValue.StartsWith(Value, StringComparison.Ordinal);
case ValueComparisonMode.SuffixMatch: // Value ends with
return attributeValue.EndsWith(Value, StringComparison.Ordinal);
case ValueComparisonMode.FullMatch: // Value equals
return string.Equals(attributeValue, Value, StringComparison.Ordinal);
default:
Debug.Assert(false, "Unknown value comparison.");
return false;
}
}
public enum NameComparisonMode
{
PrefixMatch = 1,
FullMatch = 4,
}
public enum ValueComparisonMode
{
None,
PrefixMatch,
SuffixMatch,
FullMatch,
}
}
public enum TagStructure
{
}
public class RazorDiagnostic
{
public RazorDiagnosticSeverity Severity { get; set; }
}
public enum RazorDiagnosticSeverity
{
Error,
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment