Add support for optional directives
This commit is contained in:
parent
6d18c3e85a
commit
2eba53de1b
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright(c) .NET Foundation.All rights reserved.
|
// Copyright(c) .NET Foundation.All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Evolution
|
namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
|
|
@ -27,6 +28,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
private readonly List<DirectiveTokenDescriptor> _tokenDescriptors;
|
private readonly List<DirectiveTokenDescriptor> _tokenDescriptors;
|
||||||
private readonly string _name;
|
private readonly string _name;
|
||||||
private readonly DirectiveDescriptorKind _type;
|
private readonly DirectiveDescriptorKind _type;
|
||||||
|
private bool _optional;
|
||||||
|
|
||||||
public DefaultDirectiveDescriptorBuilder(string name, DirectiveDescriptorKind type)
|
public DefaultDirectiveDescriptorBuilder(string name, DirectiveDescriptorKind type)
|
||||||
{
|
{
|
||||||
|
|
@ -39,7 +41,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
{
|
{
|
||||||
var descriptor = new DirectiveTokenDescriptor()
|
var descriptor = new DirectiveTokenDescriptor()
|
||||||
{
|
{
|
||||||
Kind = DirectiveTokenKind.Type
|
Kind = DirectiveTokenKind.Type,
|
||||||
|
Optional = _optional,
|
||||||
};
|
};
|
||||||
_tokenDescriptors.Add(descriptor);
|
_tokenDescriptors.Add(descriptor);
|
||||||
|
|
||||||
|
|
@ -50,7 +53,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
{
|
{
|
||||||
var descriptor = new DirectiveTokenDescriptor()
|
var descriptor = new DirectiveTokenDescriptor()
|
||||||
{
|
{
|
||||||
Kind = DirectiveTokenKind.Member
|
Kind = DirectiveTokenKind.Member,
|
||||||
|
Optional = _optional,
|
||||||
};
|
};
|
||||||
_tokenDescriptors.Add(descriptor);
|
_tokenDescriptors.Add(descriptor);
|
||||||
|
|
||||||
|
|
@ -61,13 +65,26 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
{
|
{
|
||||||
var descriptor = new DirectiveTokenDescriptor()
|
var descriptor = new DirectiveTokenDescriptor()
|
||||||
{
|
{
|
||||||
Kind = DirectiveTokenKind.String
|
Kind = DirectiveTokenKind.String,
|
||||||
|
Optional = _optional,
|
||||||
};
|
};
|
||||||
_tokenDescriptors.Add(descriptor);
|
_tokenDescriptors.Add(descriptor);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IDirectiveDescriptorBuilder BeginOptionals()
|
||||||
|
{
|
||||||
|
if (_optional)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
Resources.FormatDirectiveDescriptor_BeginOptionalsAlreadyInvoked(nameof(BeginOptionals)));
|
||||||
|
}
|
||||||
|
|
||||||
|
_optional = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public DirectiveDescriptor Build()
|
public DirectiveDescriptor Build()
|
||||||
{
|
{
|
||||||
var descriptor = new DirectiveDescriptor
|
var descriptor = new DirectiveDescriptor
|
||||||
|
|
|
||||||
|
|
@ -6,5 +6,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
public class DirectiveTokenDescriptor
|
public class DirectiveTokenDescriptor
|
||||||
{
|
{
|
||||||
public DirectiveTokenKind Kind { get; set; }
|
public DirectiveTokenKind Kind { get; set; }
|
||||||
|
|
||||||
|
public bool Optional { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
}
|
}
|
||||||
|
|
||||||
return descriptorX != null &&
|
return descriptorX != null &&
|
||||||
descriptorX.Kind == descriptorY.Kind;
|
descriptorX.Kind == descriptorY.Kind &&
|
||||||
|
descriptorX.Optional == descriptorY.Optional;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetHashCode(DirectiveTokenDescriptor descriptor)
|
public int GetHashCode(DirectiveTokenDescriptor descriptor)
|
||||||
|
|
@ -33,7 +34,11 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
throw new ArgumentNullException(nameof(descriptor));
|
throw new ArgumentNullException(nameof(descriptor));
|
||||||
}
|
}
|
||||||
|
|
||||||
return descriptor.Kind.GetHashCode();
|
var hashCodeCombiner = HashCodeCombiner.Start();
|
||||||
|
hashCodeCombiner.Add(descriptor.Kind);
|
||||||
|
hashCodeCombiner.Add(descriptor.Optional ? 1 : 0);
|
||||||
|
|
||||||
|
return hashCodeCombiner.CombinedHash;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
|
|
||||||
IDirectiveDescriptorBuilder AddString();
|
IDirectiveDescriptorBuilder AddString();
|
||||||
|
|
||||||
|
IDirectiveDescriptorBuilder BeginOptionals();
|
||||||
|
|
||||||
DirectiveDescriptor Build();
|
DirectiveDescriptor Build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
||||||
private Dictionary<CSharpKeyword, Action<bool>> _keywordParsers = new Dictionary<CSharpKeyword, Action<bool>>();
|
private Dictionary<CSharpKeyword, Action<bool>> _keywordParsers = new Dictionary<CSharpKeyword, Action<bool>>();
|
||||||
|
|
||||||
public CSharpCodeParser(ParserContext context)
|
public CSharpCodeParser(ParserContext context)
|
||||||
: this (directiveDescriptors: Enumerable.Empty<DirectiveDescriptor>(), context: context)
|
: this(directiveDescriptors: Enumerable.Empty<DirectiveDescriptor>(), context: context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,7 +223,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
||||||
// No "@" => Jump straight to AfterTransition
|
// No "@" => Jump straight to AfterTransition
|
||||||
AfterTransition();
|
AfterTransition();
|
||||||
}
|
}
|
||||||
|
|
||||||
Output(SpanKind.Code);
|
Output(SpanKind.Code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1507,7 +1507,11 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
||||||
Output(SpanKind.Markup, AcceptedCharacters.WhiteSpace);
|
Output(SpanKind.Markup, AcceptedCharacters.WhiteSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EndOfFile)
|
if (tokenDescriptor.Optional && (EndOfFile || At(CSharpSymbolType.NewLine)))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (EndOfFile)
|
||||||
{
|
{
|
||||||
Context.ErrorSink.OnError(
|
Context.ErrorSink.OnError(
|
||||||
CurrentStart,
|
CurrentStart,
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,22 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
||||||
return GetString("RazorProject_PathMustStartWithForwardSlash");
|
return GetString("RazorProject_PathMustStartWithForwardSlash");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The method '{0}' has already been invoked.
|
||||||
|
/// </summary>
|
||||||
|
internal static string DirectiveDescriptor_BeginOptionalsAlreadyInvoked
|
||||||
|
{
|
||||||
|
get { return GetString("DirectiveDescriptor_BeginOptionalsAlreadyInvoked"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The method '{0}' has already been invoked.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatDirectiveDescriptor_BeginOptionalsAlreadyInvoked(object p0)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.CurrentCulture, GetString("DirectiveDescriptor_BeginOptionalsAlreadyInvoked"), p0);
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetString(string name, params string[] formatterNames)
|
private static string GetString(string name, params string[] formatterNames)
|
||||||
{
|
{
|
||||||
var value = _resourceManager.GetString(name);
|
var value = _resourceManager.GetString(name);
|
||||||
|
|
|
||||||
|
|
@ -150,4 +150,7 @@
|
||||||
<data name="RazorProject_PathMustStartWithForwardSlash" xml:space="preserve">
|
<data name="RazorProject_PathMustStartWithForwardSlash" xml:space="preserve">
|
||||||
<value>Path must begin with a forward slash '/'.</value>
|
<value>Path must begin with a forward slash '/'.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="DirectiveDescriptor_BeginOptionalsAlreadyInvoked" xml:space="preserve">
|
||||||
|
<value>The method '{0}' has already been invoked.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -734,6 +734,23 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
||||||
.Accepts(AcceptedCharacters.None)));
|
.Accepts(AcceptedCharacters.None)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void OptionalDirectiveTokens_AreSkipped()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var descriptor = DirectiveDescriptorBuilder.Create("custom").BeginOptionals().AddString().Build();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
ParseCodeBlockTest(
|
||||||
|
"@custom ",
|
||||||
|
new[] { descriptor },
|
||||||
|
new DirectiveBlock(
|
||||||
|
new DirectiveChunkGenerator(descriptor),
|
||||||
|
Factory.CodeTransition(),
|
||||||
|
Factory.MetaCode("custom").Accepts(AcceptedCharacters.None),
|
||||||
|
Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace)));
|
||||||
|
}
|
||||||
|
|
||||||
internal virtual void ParseCodeBlockTest(
|
internal virtual void ParseCodeBlockTest(
|
||||||
string document,
|
string document,
|
||||||
IEnumerable<DirectiveDescriptor> descriptors,
|
IEnumerable<DirectiveDescriptor> descriptors,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue