Split the functions/section/inherits directives

This commit is contained in:
Ryan Nowak 2017-06-09 18:13:44 -07:00
parent 27ac5da6d5
commit 22d52f2a3c
30 changed files with 716 additions and 415 deletions

View File

@ -15,6 +15,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
NamespaceDirective.Register(builder); NamespaceDirective.Register(builder);
PageDirective.Register(builder); PageDirective.Register(builder);
FunctionsDirective.Register(builder);
InheritsDirective.Register(builder);
SectionDirective.Register(builder);
builder.AddTargetExtension(new InjectDirectiveTargetExtension()); builder.AddTargetExtension(new InjectDirectiveTargetExtension());
builder.AddTargetExtension(new TemplateTargetExtension() builder.AddTargetExtension(new TemplateTargetExtension()
{ {

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.AspNetCore.Razor.Language.Legacy; using Microsoft.AspNetCore.Razor.Language.Legacy;
namespace Microsoft.AspNetCore.Razor.Language namespace Microsoft.AspNetCore.Razor.Language
@ -55,7 +56,7 @@ namespace Microsoft.AspNetCore.Razor.Language
if (_nestedLevel > 0) if (_nestedLevel > 0)
{ {
var directiveStart = block.Children.First(child => !child.IsBlock && ((Span)child).Kind == SpanKindInternal.Transition).Start; var directiveStart = block.Children.First(child => !child.IsBlock && ((Span)child).Kind == SpanKindInternal.Transition).Start;
var errorLength = /* @ */ 1 + CSharpCodeParser.SectionDirectiveDescriptor.Directive.Length; var errorLength = /* @ */ 1 + SectionDirective.Directive.Directive.Length;
_errorSink.OnError( _errorSink.OnError(
directiveStart, directiveStart,
LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS), LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS),

View File

@ -0,0 +1,20 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.Language.Legacy;
namespace Microsoft.AspNetCore.Razor.Language.Extensions
{
public static class FunctionsDirective
{
public static readonly DirectiveDescriptor Directive = DirectiveDescriptor.CreateDirective(
SyntaxConstants.CSharp.FunctionsKeyword,
DirectiveKind.CodeBlock);
public static void Register(IRazorEngineBuilder builder)
{
builder.AddDirective(Directive);
builder.Features.Add(new FunctionsDirectivePass());
}
}
}

View File

@ -0,0 +1,29 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Razor.Language.Extensions
{
public class FunctionsDirectivePass : RazorIRPassBase, IRazorDirectiveClassifierPass
{
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
{
var @class = irDocument.FindPrimaryClass();
if (@class == null)
{
return;
}
foreach (var functions in irDocument.FindDirectiveReferences(FunctionsDirective.Directive))
{
functions.Remove();
for (var i = 0; i < functions.Node.Children.Count; i++)
{
@class.Children.Add(functions.Node.Children[i]);
}
}
}
}
}

View File

@ -0,0 +1,21 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.Language.Legacy;
namespace Microsoft.AspNetCore.Razor.Language.Extensions
{
public static class InheritsDirective
{
public static readonly DirectiveDescriptor Directive = DirectiveDescriptor.CreateDirective(
SyntaxConstants.CSharp.InheritsKeyword,
DirectiveKind.SingleLine,
builder => builder.AddTypeToken());
public static void Register(IRazorEngineBuilder builder)
{
builder.AddDirective(Directive);
builder.Features.Add(new InheritsDirectivePass());
}
}
}

View File

@ -0,0 +1,34 @@
// 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.Linq;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Razor.Language.Extensions
{
public class InheritsDirectivePass : RazorIRPassBase, IRazorDirectiveClassifierPass
{
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
{
var @class = irDocument.FindPrimaryClass();
if (@class == null)
{
return;
}
foreach (var inherits in irDocument.FindDirectiveReferences(InheritsDirective.Directive))
{
inherits.Remove();
var token = ((DirectiveIRNode)inherits.Node).Tokens.FirstOrDefault();
if (token != null)
{
@class.BaseType = token.Content;
break;
}
}
}
}
}

View File

@ -0,0 +1,21 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.Language.Legacy;
namespace Microsoft.AspNetCore.Razor.Language.Extensions
{
public static class SectionDirective
{
public static readonly DirectiveDescriptor Directive = DirectiveDescriptor.CreateDirective(
SyntaxConstants.CSharp.SectionKeyword,
DirectiveKind.RazorBlock,
builder => builder.AddMemberToken());
public static void Register(IRazorEngineBuilder builder)
{
builder.AddDirective(Directive);
builder.Features.Add(new SectionDirectivePass());
}
}
}

View File

@ -1,53 +1,25 @@
// 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.Linq; using System.Linq;
using Microsoft.AspNetCore.Razor.Language.Intermediate; using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Microsoft.AspNetCore.Razor.Language.Legacy;
namespace Microsoft.AspNetCore.Razor.Language namespace Microsoft.AspNetCore.Razor.Language.Extensions
{ {
internal class DefaultDirectiveIRPass : RazorIRPassBase, IRazorDirectiveClassifierPass public class SectionDirectivePass : RazorIRPassBase, IRazorDirectiveClassifierPass
{ {
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument) protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
{ {
var parserOptions = irDocument.Options; var @class = irDocument.FindPrimaryClass();
if (@class == null)
var designTime = parserOptions.DesignTime;
var classNode = irDocument.FindPrimaryClass();
if (classNode == null)
{ {
return; return;
} }
foreach (var functions in irDocument.FindDirectiveReferences(CSharpCodeParser.FunctionsDirectiveDescriptor)) foreach (var section in irDocument.FindDirectiveReferences(SectionDirective.Directive))
{ {
functions.Remove(); var lambdaContent = irDocument.Options.DesignTime ? "__razor_section_writer" : string.Empty;
for (var i =0; i < functions.Node.Children.Count; i++)
{
classNode.Children.Add(functions.Node.Children[i]);
}
}
foreach (var inherits in irDocument.FindDirectiveReferences(CSharpCodeParser.InheritsDirectiveDescriptor).Reverse())
{
inherits.Remove();
var token = ((DirectiveIRNode)inherits.Node).Tokens.FirstOrDefault();
if (token != null)
{
classNode.BaseType = token.Content;
break;
}
}
foreach (var section in irDocument.FindDirectiveReferences(CSharpCodeParser.SectionDirectiveDescriptor))
{
var lambdaContent = designTime ? "__razor_section_writer" : string.Empty;
var sectionName = ((DirectiveIRNode)section.Node).Tokens.FirstOrDefault()?.Content; var sectionName = ((DirectiveIRNode)section.Node).Tokens.FirstOrDefault()?.Content;
var builder = RazorIRBuilder.Create(new CSharpCodeIRNode()); var builder = RazorIRBuilder.Create(new CSharpCodeIRNode());

View File

@ -13,20 +13,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
private static readonly Func<CSharpSymbol, bool> IsValidStatementSpacingSymbol = private static readonly Func<CSharpSymbol, bool> IsValidStatementSpacingSymbol =
IsSpacingToken(includeNewLines: true, includeComments: true); IsSpacingToken(includeNewLines: true, includeComments: true);
internal static readonly DirectiveDescriptor SectionDirectiveDescriptor = DirectiveDescriptor.CreateDirective(
SyntaxConstants.CSharp.SectionKeyword,
DirectiveKind.RazorBlock,
builder => builder.AddMemberToken());
internal static readonly DirectiveDescriptor FunctionsDirectiveDescriptor = DirectiveDescriptor.CreateDirective(
SyntaxConstants.CSharp.FunctionsKeyword,
DirectiveKind.CodeBlock);
internal static readonly DirectiveDescriptor InheritsDirectiveDescriptor = DirectiveDescriptor.CreateDirective(
SyntaxConstants.CSharp.InheritsKeyword,
DirectiveKind.SingleLine,
builder => builder.AddTypeToken());
internal static readonly DirectiveDescriptor AddTagHelperDirectiveDescriptor = DirectiveDescriptor.CreateDirective( internal static readonly DirectiveDescriptor AddTagHelperDirectiveDescriptor = DirectiveDescriptor.CreateDirective(
SyntaxConstants.CSharp.AddTagHelperKeyword, SyntaxConstants.CSharp.AddTagHelperKeyword,
DirectiveKind.SingleLine, DirectiveKind.SingleLine,
@ -42,11 +28,8 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
DirectiveKind.SingleLine, DirectiveKind.SingleLine,
builder => builder.AddStringToken()); builder => builder.AddStringToken());
internal static readonly IEnumerable<DirectiveDescriptor> DefaultDirectiveDescriptors = new[] internal static readonly IEnumerable<DirectiveDescriptor> DefaultDirectiveDescriptors = new DirectiveDescriptor[]
{ {
SectionDirectiveDescriptor,
FunctionsDirectiveDescriptor,
InheritsDirectiveDescriptor,
}; };
internal static ISet<string> DefaultKeywords = new HashSet<string>() internal static ISet<string> DefaultKeywords = new HashSet<string>()
@ -63,9 +46,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"switch", "switch",
"lock", "lock",
"using", "using",
"section",
"inherits",
"functions",
"namespace", "namespace",
"class", "class",
}; };
@ -76,16 +56,26 @@ namespace Microsoft.AspNetCore.Razor.Language.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(directives: Enumerable.Empty<DirectiveDescriptor>(), context: context)
{ {
} }
public CSharpCodeParser(IEnumerable<DirectiveDescriptor> directiveDescriptors, ParserContext context) public CSharpCodeParser(IEnumerable<DirectiveDescriptor> directives, ParserContext context)
: base(context.ParseOnlyLeadingDirectives ? FirstDirectiveCSharpLanguageCharacteristics.Instance : CSharpLanguageCharacteristics.Instance, context) : base(context.ParseOnlyLeadingDirectives ? FirstDirectiveCSharpLanguageCharacteristics.Instance : CSharpLanguageCharacteristics.Instance, context)
{ {
if (directives == null)
{
throw new ArgumentNullException(nameof(directives));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
Keywords = new HashSet<string>(); Keywords = new HashSet<string>();
SetUpKeywords(); SetUpKeywords();
SetupDirectives(directiveDescriptors); SetupDirectives(directives);
SetUpExpressions(); SetUpExpressions();
} }

View File

@ -47,7 +47,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
var other = obj as ImplicitExpressionEditHandler; var other = obj as ImplicitExpressionEditHandler;
return base.Equals(other) && return base.Equals(other) &&
_keywords.SetEquals(other._keywords) &&
AcceptTrailingDot == other.AcceptTrailingDot; AcceptTrailingDot == other.AcceptTrailingDot;
} }
@ -55,7 +54,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
// Hash code should include only immutable properties and base has none. // Hash code should include only immutable properties and base has none.
var hashCodeCombiner = HashCodeCombiner.Start(); var hashCodeCombiner = HashCodeCombiner.Start();
hashCodeCombiner.Add(Keywords);
hashCodeCombiner.Add(AcceptTrailingDot); hashCodeCombiner.Add(AcceptTrailingDot);
return hashCodeCombiner; return hashCodeCombiner;

View File

@ -70,7 +70,6 @@ namespace Microsoft.AspNetCore.Razor.Language
// IR Passes // IR Passes
builder.Features.Add(new DefaultDocumentClassifierPass()); builder.Features.Add(new DefaultDocumentClassifierPass());
builder.Features.Add(new DefaultDirectiveIRPass());
builder.Features.Add(new DirectiveRemovalIROptimizationPass()); builder.Features.Add(new DirectiveRemovalIROptimizationPass());
// Default Runtime Targets // Default Runtime Targets

View File

@ -5,6 +5,7 @@ using System;
using System.IO; using System.IO;
using System.Text; using System.Text;
using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.AspNetCore.Razor.Language.Intermediate; using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Xunit; using Xunit;
@ -239,6 +240,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{ {
// Notice we're not registering the ModelDirective.Pass here so we can run it on demand. // Notice we're not registering the ModelDirective.Pass here so we can run it on demand.
b.AddDirective(ModelDirective.Directive); b.AddDirective(ModelDirective.Directive);
// There's some special interaction with the inherits directive
InheritsDirective.Register(b);
}); });
} }

View File

@ -1,127 +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 Microsoft.AspNetCore.Razor.Language.Legacy;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Language
{
public class DefaultDirectiveSyntaxTreePassTest
{
[Fact]
public void Execute_DoesNotRecreateSyntaxTreeWhenNoErrors()
{
// Arrange
var engine = RazorEngine.Create();
var pass = new DefaultDirectiveSyntaxTreePass()
{
Engine = engine,
};
var content =
@"
@section Foo {
}";
var sourceDocument = TestRazorSourceDocument.Create(content);
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
// Act
var outputTree = pass.Execute(codeDocument, originalTree);
// Assert
Assert.Empty(originalTree.Diagnostics);
Assert.Same(originalTree, outputTree);
Assert.Empty(outputTree.Diagnostics);
}
[Fact]
public void Execute_LogsErrorsForNestedSections()
{
// Arrange
var expectedErrors = new[] {
new RazorError(
LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS),
new SourceLocation(18 + Environment.NewLine.Length * 2, 2, 4),
length: 8),
new RazorError(
LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS),
new SourceLocation(41 + Environment.NewLine.Length * 4, 4, 4),
length: 8),
};
var expectedDiagnostics = expectedErrors.Select(error => RazorDiagnostic.Create(error));
var engine = RazorEngine.Create();
var pass = new DefaultDirectiveSyntaxTreePass()
{
Engine = engine,
};
var content =
@"
@section Foo {
@section Bar {
}
@section Baz {
}
}";
var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null);
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
// Act
var outputTree = pass.Execute(codeDocument, originalTree);
// Assert
Assert.Empty(originalTree.Diagnostics);
Assert.NotSame(originalTree, outputTree);
Assert.Equal(expectedDiagnostics, outputTree.Diagnostics);
}
[Fact]
public void Execute_CombinesErrorsWhenNestedSections()
{
// Arrange
var expectedErrors = new[] {
new RazorError("Test Error", SourceLocation.Zero, 3),
new RazorError(
LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS),
new SourceLocation(18 + Environment.NewLine.Length * 2, 2, 4),
length: 8),
new RazorError(
LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS),
new SourceLocation(41 + Environment.NewLine.Length * 4, 4, 4),
length: 8),
};
var expectedDiagnostics = expectedErrors.Select(error => RazorDiagnostic.Create(error)).ToList();
var engine = RazorEngine.Create();
var pass = new DefaultDirectiveSyntaxTreePass()
{
Engine = engine,
};
var content =
@"
@section Foo {
@section Bar {
}
@section Baz {
}
}";
var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null);
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
var erroredOriginalTree = RazorSyntaxTree.Create(
originalTree.Root,
originalTree.Source,
new[] { expectedDiagnostics[0] },
originalTree.Options);
// Act
var outputTree = pass.Execute(codeDocument, erroredOriginalTree);
// Assert
Assert.Empty(originalTree.Diagnostics);
Assert.NotSame(originalTree, outputTree);
Assert.Equal(expectedDiagnostics, outputTree.Diagnostics);
}
}
}

View File

@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Xunit; using Xunit;
using static Microsoft.AspNetCore.Razor.Language.Intermediate.RazorIRAssert; using static Microsoft.AspNetCore.Razor.Language.Intermediate.RazorIRAssert;
using Moq; using Moq;
using Microsoft.AspNetCore.Razor.Language.Extensions;
namespace Microsoft.AspNetCore.Razor.Language namespace Microsoft.AspNetCore.Razor.Language
{ {
@ -459,6 +460,8 @@ namespace Microsoft.AspNetCore.Razor.Language
{ {
builder?.Invoke(b); builder?.Invoke(b);
FunctionsDirective.Register(b);
SectionDirective.Register(b);
b.AddTagHelpers(tagHelpers); b.AddTagHelpers(tagHelpers);
}); });

View File

@ -0,0 +1,103 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Xunit;
using static Microsoft.AspNetCore.Razor.Language.Intermediate.RazorIRAssert;
namespace Microsoft.AspNetCore.Razor.Language.Extensions
{
public class FunctionsDirectivePassTest
{
[Fact]
public void Execute_SkipsDocumentWithNoClassNode()
{
// Arrange
var engine = CreateEngine();
var pass = new FunctionsDirectivePass()
{
Engine = engine,
};
var sourceDocument = TestRazorSourceDocument.Create("@functions { var value = true; }");
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var irDocument = new DocumentIRNode();
irDocument.Children.Add(new DirectiveIRNode() { Descriptor = FunctionsDirective.Directive, });
// Act
pass.Execute(codeDocument, irDocument);
// Assert
Children(
irDocument,
node => Assert.IsType<DirectiveIRNode>(node));
}
[Fact]
public void Execute_MovesStatementsToClassLevel()
{
// Arrange
var engine = CreateEngine();
var pass = new FunctionsDirectivePass()
{
Engine = engine,
};
var sourceDocument = TestRazorSourceDocument.Create("@functions { var value = true; }");
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var irDocument = Lower(codeDocument, engine);
// Act
pass.Execute(codeDocument, irDocument);
// Assert
Children(
irDocument,
node => Assert.IsType<ChecksumIRNode>(node),
node => Assert.IsType<NamespaceDeclarationIRNode>(node));
var @namespace = irDocument.Children[1];
Children(
@namespace,
node => Assert.IsType<ClassDeclarationIRNode>(node));
var @class = @namespace.Children[0];
Children(
@class,
node => Assert.IsType<MethodDeclarationIRNode>(node),
node => CSharpCode(" var value = true; ", node));
var method = (MethodDeclarationIRNode)@class.Children[0];
Assert.Empty(method.Children);
}
private static RazorEngine CreateEngine()
{
return RazorEngine.Create(b =>
{
FunctionsDirective.Register(b);
});
}
private static DocumentIRNode Lower(RazorCodeDocument codeDocument, RazorEngine engine)
{
for (var i = 0; i < engine.Phases.Count; i++)
{
var phase = engine.Phases[i];
phase.Execute(codeDocument);
if (phase is IRazorDocumentClassifierPhase)
{
break;
}
}
var irDocument = codeDocument.GetIRDocument();
Assert.NotNull(irDocument);
return irDocument;
}
}
}

View File

@ -0,0 +1,98 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Xunit;
using static Microsoft.AspNetCore.Razor.Language.Intermediate.RazorIRAssert;
namespace Microsoft.AspNetCore.Razor.Language.Extensions
{
public class InheritsDirectivePassTest
{
[Fact]
public void Execute_SkipsDocumentWithNoClassNode()
{
// Arrange
var engine = CreateEngine();
var pass = new InheritsDirectivePass()
{
Engine = engine,
};
var sourceDocument = TestRazorSourceDocument.Create("@inherits Hello<World[]>");
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var irDocument = new DocumentIRNode();
irDocument.Children.Add(new DirectiveIRNode() { Descriptor = FunctionsDirective.Directive, });
// Act
pass.Execute(codeDocument, irDocument);
// Assert
Children(
irDocument,
node => Assert.IsType<DirectiveIRNode>(node));
}
[Fact]
public void Execute_Inherits_SetsClassDeclarationBaseType()
{
// Arrange
var engine = CreateEngine();
var pass = new InheritsDirectivePass()
{
Engine = engine,
};
var content = "@inherits Hello<World[]>";
var sourceDocument = TestRazorSourceDocument.Create(content);
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var irDocument = Lower(codeDocument, engine);
// Act
pass.Execute(codeDocument, irDocument);
// Assert
Children(
irDocument,
node => Assert.IsType<ChecksumIRNode>(node),
node => Assert.IsType<NamespaceDeclarationIRNode>(node));
var @namespace = irDocument.Children[1];
Children(
@namespace,
node => Assert.IsType<ClassDeclarationIRNode>(node));
var @class = (ClassDeclarationIRNode)@namespace.Children[0];
Assert.Equal("Hello<World[]>", @class.BaseType);
}
private static RazorEngine CreateEngine()
{
return RazorEngine.Create(b =>
{
InheritsDirective.Register(b);
});
}
private static DocumentIRNode Lower(RazorCodeDocument codeDocument, RazorEngine engine)
{
for (var i = 0; i < engine.Phases.Count; i++)
{
var phase = engine.Phases[i];
phase.Execute(codeDocument);
if (phase is IRazorDocumentClassifierPhase)
{
break;
}
}
var irDocument = codeDocument.GetIRDocument();
Assert.NotNull(irDocument);
return irDocument;
}
}
}

View File

@ -5,140 +5,127 @@ using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Xunit; using Xunit;
using static Microsoft.AspNetCore.Razor.Language.Intermediate.RazorIRAssert; using static Microsoft.AspNetCore.Razor.Language.Intermediate.RazorIRAssert;
namespace Microsoft.AspNetCore.Razor.Language namespace Microsoft.AspNetCore.Razor.Language.Extensions
{ {
public class DefaultDirectiveIRPassTest public class SectionDirectivePassTest
{ {
[Fact] [Fact]
public void Execute_Inherits_SetsClassDeclarationBaseType() public void Execute_SkipsDocumentWithNoClassNode()
{ {
// Arrange // Arrange
var content = "@inherits Hello<World[]>"; var engine = CreateEngine();
var sourceDocument = TestRazorSourceDocument.Create(content); var pass = new SectionDirectivePass()
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var irDocument = Lower(codeDocument);
var defaultEngine = RazorEngine.Create();
var pass = new DefaultDirectiveIRPass()
{ {
Engine = defaultEngine, Engine = engine,
}; };
var sourceDocument = TestRazorSourceDocument.Create("@section Header { <p>Hello World</p> }");
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var irDocument = new DocumentIRNode();
irDocument.Children.Add(new DirectiveIRNode() { Descriptor = SectionDirective.Directive, });
// Act // Act
pass.Execute(codeDocument, irDocument); pass.Execute(codeDocument, irDocument);
// Assert // Assert
Children(irDocument, Children(
node => Assert.IsType<ChecksumIRNode>(node), irDocument,
node => Assert.IsType<NamespaceDeclarationIRNode>(node)); node => Assert.IsType<DirectiveIRNode>(node));
var @namespace = irDocument.Children[1];
Children(@namespace,
node => Assert.IsType<ClassDeclarationIRNode>(node));
var @class = (ClassDeclarationIRNode)@namespace.Children[0];
Assert.Equal("Hello<World[]>", @class.BaseType);
} }
[Fact] [Fact]
public void Execute_Functions_MovesStatementToClassLevel() public void Execute_WrapsStatementInDefineSection()
{ {
// Arrange // Arrange
var content = "@functions { var value = true; }"; var engine = CreateEngine();
var sourceDocument = TestRazorSourceDocument.Create(content); var pass = new SectionDirectivePass()
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var irDocument = Lower(codeDocument);
var defaultEngine = RazorEngine.Create();
var pass = new DefaultDirectiveIRPass()
{ {
Engine = defaultEngine, Engine = engine,
}; };
// Act
pass.Execute(codeDocument, irDocument);
// Assert
Children(irDocument,
node => Assert.IsType<ChecksumIRNode>(node),
node => Assert.IsType<NamespaceDeclarationIRNode>(node));
var @namespace = irDocument.Children[1];
Children(@namespace,
node => Assert.IsType<ClassDeclarationIRNode>(node));
var @class = @namespace.Children[0];
Children(@class,
node => Assert.IsType<MethodDeclarationIRNode>(node),
node => CSharpCode(" var value = true; ", node));
var method = (MethodDeclarationIRNode)@class.Children[0];
Assert.Empty(method.Children);
}
[Fact]
public void Execute_Section_WrapsStatementInDefineSection()
{
// Arrange
var content = "@section Header { <p>Hello World</p> }"; var content = "@section Header { <p>Hello World</p> }";
var sourceDocument = TestRazorSourceDocument.Create(content); var sourceDocument = TestRazorSourceDocument.Create(content);
var codeDocument = RazorCodeDocument.Create(sourceDocument); var codeDocument = RazorCodeDocument.Create(sourceDocument);
var irDocument = Lower(codeDocument);
var defaultEngine = RazorEngine.Create(); var irDocument = Lower(codeDocument, engine);
var pass = new DefaultDirectiveIRPass()
{
Engine = defaultEngine,
};
// Act // Act
pass.Execute(codeDocument, irDocument); pass.Execute(codeDocument, irDocument);
// Assert // Assert
Children(irDocument, Children(
irDocument,
node => Assert.IsType<ChecksumIRNode>(node), node => Assert.IsType<ChecksumIRNode>(node),
node => Assert.IsType<NamespaceDeclarationIRNode>(node)); node => Assert.IsType<NamespaceDeclarationIRNode>(node));
var @namespace = irDocument.Children[1]; var @namespace = irDocument.Children[1];
Children(@namespace, Children(
@namespace,
node => Assert.IsType<ClassDeclarationIRNode>(node)); node => Assert.IsType<ClassDeclarationIRNode>(node));
var @class = @namespace.Children[0]; var @class = @namespace.Children[0];
var method = SingleChild<MethodDeclarationIRNode>(@class); var method = SingleChild<MethodDeclarationIRNode>(@class);
Children(method, Children(
method,
node => CSharpCode("DefineSection(\"Header\", async () => {", node), node => CSharpCode("DefineSection(\"Header\", async () => {", node),
node => Html(" <p>Hello World</p> ", node), node => Html(" <p>Hello World</p> ", node),
node => CSharpCode("});", node)); node => CSharpCode("});", node));
} }
[Fact] [Fact]
public void Execute_Section_DesignTime_WrapsStatementInBackwardsCompatibleDefineSection() public void Execute_DesignTime_WrapsStatementInBackwardsCompatibleDefineSection()
{ {
// Arrange // Arrange
var engine = CreateDesignTimeEngine();
var pass = new SectionDirectivePass()
{
Engine = engine,
};
var content = "@section Header { <p>Hello World</p> }"; var content = "@section Header { <p>Hello World</p> }";
var designTimeEngine = RazorEngine.CreateDesignTime();
var sourceDocument = TestRazorSourceDocument.Create(content); var sourceDocument = TestRazorSourceDocument.Create(content);
var codeDocument = RazorCodeDocument.Create(sourceDocument); var codeDocument = RazorCodeDocument.Create(sourceDocument);
var irDocument = Lower(codeDocument, designTimeEngine);
var defaultEngine = RazorEngine.Create(); var irDocument = Lower(codeDocument, engine);
var pass = new DefaultDirectiveIRPass()
{
Engine = defaultEngine,
};
// Act // Act
pass.Execute(codeDocument, irDocument); pass.Execute(codeDocument, irDocument);
// Assert // Assert
Children(irDocument, Children(
irDocument,
node => Assert.IsType<ChecksumIRNode>(node), node => Assert.IsType<ChecksumIRNode>(node),
node => Assert.IsType<NamespaceDeclarationIRNode>(node)); node => Assert.IsType<NamespaceDeclarationIRNode>(node));
var @namespace = irDocument.Children[1]; var @namespace = irDocument.Children[1];
Children(@namespace, Children(
@namespace,
node => Assert.IsType<ClassDeclarationIRNode>(node)); node => Assert.IsType<ClassDeclarationIRNode>(node));
var @class = @namespace.Children[0]; var @class = @namespace.Children[0];
var method = SingleChild<MethodDeclarationIRNode>(@class); var method = SingleChild<MethodDeclarationIRNode>(@class);
Children(method, Children(
method,
node => CSharpCode("DefineSection(\"Header\", async (__razor_section_writer) => {", node), node => CSharpCode("DefineSection(\"Header\", async (__razor_section_writer) => {", node),
node => Html(" <p>Hello World</p> ", node), node => Html(" <p>Hello World</p> ", node),
node => CSharpCode("});", node)); node => CSharpCode("});", node));
} }
private static DocumentIRNode Lower(RazorCodeDocument codeDocument) private static RazorEngine CreateEngine()
{ {
var engine = RazorEngine.Create(); return RazorEngine.Create(b =>
{
SectionDirective.Register(b);
});
}
return Lower(codeDocument, engine); private static RazorEngine CreateDesignTimeEngine()
{
return RazorEngine.CreateDesignTime(b =>
{
SectionDirective.Register(b);
});
} }
private static DocumentIRNode Lower(RazorCodeDocument codeDocument, RazorEngine engine) private static DocumentIRNode Lower(RazorCodeDocument codeDocument, RazorEngine engine)

View File

@ -4,6 +4,7 @@
using Microsoft.AspNetCore.Razor.Language.CodeGeneration; using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Legacy; using Microsoft.AspNetCore.Razor.Language.Legacy;
using Xunit; using Xunit;
using static Microsoft.AspNetCore.Razor.Language.Intermediate.RazorIRAssert;
namespace Microsoft.AspNetCore.Razor.Language.Extensions namespace Microsoft.AspNetCore.Razor.Language.Extensions
{ {

View File

@ -889,6 +889,10 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
// Some of these tests use templates // Some of these tests use templates
builder.AddTargetExtension(new TemplateTargetExtension()); builder.AddTargetExtension(new TemplateTargetExtension());
FunctionsDirective.Register(builder);
InheritsDirective.Register(builder);
SectionDirective.Register(builder);
}); });
var document = CreateCodeDocument(); var document = CreateCodeDocument();
@ -911,6 +915,10 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
// Some of these tests use templates // Some of these tests use templates
builder.AddTargetExtension(new TemplateTargetExtension()); builder.AddTargetExtension(new TemplateTargetExtension());
FunctionsDirective.Register(builder);
InheritsDirective.Register(builder);
SectionDirective.Register(builder);
}); });
var document = CreateCodeDocument(); var document = CreateCodeDocument();
@ -933,6 +941,10 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
// Some of these tests use templates // Some of these tests use templates
builder.AddTargetExtension(new TemplateTargetExtension()); builder.AddTargetExtension(new TemplateTargetExtension());
FunctionsDirective.Register(builder);
InheritsDirective.Register(builder);
SectionDirective.Register(builder);
}); });
var document = CreateCodeDocument(); var document = CreateCodeDocument();
@ -955,6 +967,10 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
// Some of these tests use templates // Some of these tests use templates
builder.AddTargetExtension(new TemplateTargetExtension()); builder.AddTargetExtension(new TemplateTargetExtension());
FunctionsDirective.Register(builder);
InheritsDirective.Register(builder);
SectionDirective.Register(builder);
}); });
var document = CreateCodeDocument(); var document = CreateCodeDocument();

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Razor.Language.Legacy namespace Microsoft.AspNetCore.Razor.Language.Legacy
@ -14,12 +15,13 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
ParseBlockTest( ParseBlockTest(
"@functions{", "@functions{",
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor), new[] { FunctionsDirective.Directive, },
new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None)), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None)),
new RazorError( new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(CSharpCodeParser.FunctionsDirectiveDescriptor.Directive, "}", "{"), LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(FunctionsDirective.Directive.Directive, "}", "{"),
new SourceLocation(10, 0, 10), new SourceLocation(10, 0, 10),
length: 1)); length: 1));
} }
@ -28,12 +30,13 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
public void SectionDirectiveAutoCompleteAtEOF() public void SectionDirectiveAutoCompleteAtEOF()
{ {
ParseBlockTest("@section Header {", ParseBlockTest("@section Header {",
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new[] { SectionDirective.Directive, },
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "Header", CSharpSymbolType.Identifier) Factory.Span(SpanKindInternal.Code, "Header", CSharpSymbolType.Identifier)
.AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First()), .AsDirectiveToken(SectionDirective.Directive.Tokens.First()),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -65,8 +68,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void FunctionsDirectiveAutoCompleteAtStartOfFile() public void FunctionsDirectiveAutoCompleteAtStartOfFile()
{ {
ParseBlockTest("@functions{" + Environment.NewLine + "foo", ParseBlockTest(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor), "@functions{" + Environment.NewLine + "foo",
new[] { FunctionsDirective.Directive, },
new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
@ -82,11 +87,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
ParseBlockTest("@section Header {" + Environment.NewLine ParseBlockTest("@section Header {" + Environment.NewLine
+ "<p>Foo</p>", + "<p>Foo</p>",
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new[] { SectionDirective.Directive, },
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "Header", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First()), Factory.Span(SpanKindInternal.Code, "Header", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens.First()),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Razor.Language.Legacy namespace Microsoft.AspNetCore.Razor.Language.Legacy
@ -987,56 +988,66 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
} }
[Fact] [Fact]
public void InheritsDirective() public void ParseBlock_InheritsDirective()
{ {
ParseBlockTest("@inherits System.Web.WebPages.WebPage", ParseCodeBlockTest(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), "@inherits System.Web.WebPages.WebPage",
new[] { InheritsDirective.Directive, },
new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "System.Web.WebPages.WebPage", markup: false).AsDirectiveToken(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))); Factory.Span(SpanKindInternal.Code, "System.Web.WebPages.WebPage", markup: false).AsDirectiveToken(InheritsDirective.Directive.Tokens.First())));
} }
[Fact] [Fact]
public void InheritsDirectiveSupportsArrays() public void InheritsDirectiveSupportsArrays()
{ {
ParseBlockTest("@inherits string[[]][]", ParseCodeBlockTest(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), "@inherits string[[]][]",
new[] { InheritsDirective.Directive, },
new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "string[[]][]", markup: false).AsDirectiveToken(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))); Factory.Span(SpanKindInternal.Code, "string[[]][]", markup: false).AsDirectiveToken(InheritsDirective.Directive.Tokens.First())));
} }
[Fact] [Fact]
public void InheritsDirectiveSupportsNestedGenerics() public void InheritsDirectiveSupportsNestedGenerics()
{ {
ParseBlockTest("@inherits System.Web.Mvc.WebViewPage<IEnumerable<MvcApplication2.Models.RegisterModel>>", ParseCodeBlockTest(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), "@inherits System.Web.Mvc.WebViewPage<IEnumerable<MvcApplication2.Models.RegisterModel>>",
new[] { InheritsDirective.Directive, },
new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "System.Web.Mvc.WebViewPage<IEnumerable<MvcApplication2.Models.RegisterModel>>", markup: false) Factory.Span(SpanKindInternal.Code, "System.Web.Mvc.WebViewPage<IEnumerable<MvcApplication2.Models.RegisterModel>>", markup: false)
.AsDirectiveToken(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))); .AsDirectiveToken(InheritsDirective.Directive.Tokens.First())));
} }
[Fact] [Fact]
public void InheritsDirectiveSupportsTypeKeywords() public void InheritsDirectiveSupportsTypeKeywords()
{ {
ParseBlockTest("@inherits string", ParseCodeBlockTest(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), "@inherits string",
new[] { InheritsDirective.Directive, },
new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "string", markup: false) Factory.Span(SpanKindInternal.Code, "string", markup: false)
.AsDirectiveToken(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))); .AsDirectiveToken(InheritsDirective.Directive.Tokens.First())));
} }
[Fact] [Fact]
public void FunctionsDirective() public void Parse_FunctionsDirective()
{ {
ParseBlockTest("@functions { foo(); bar(); }", ParseCodeBlockTest(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor), "@functions { foo(); bar(); }",
new[] { FunctionsDirective.Directive, },
new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
@ -1048,8 +1059,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void EmptyFunctionsDirective() public void EmptyFunctionsDirective()
{ {
ParseBlockTest("@functions { }", ParseCodeBlockTest(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor), "@functions { }",
new[] { FunctionsDirective.Directive, },
new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
@ -1059,15 +1072,17 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
} }
[Fact] [Fact]
public void SectionDirective() public void Parse_SectionDirective()
{ {
ParseBlockTest("@section Header { <p>F{o}o</p> }", ParseCodeBlockTest(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), "@section Header { <p>F{o}o</p> }",
new[] { SectionDirective.Directive, },
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "Header", CSharpSymbolType.Identifier) Factory.Span(SpanKindInternal.Code, "Header", CSharpSymbolType.Identifier)
.AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First()), .AsDirectiveToken(SectionDirective.Directive.Tokens.First()),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(

View File

@ -2,6 +2,7 @@
// 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;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Razor.Language.Legacy namespace Microsoft.AspNetCore.Razor.Language.Legacy
@ -298,8 +299,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseBlockReportsErrorIfClassBlockUnterminatedAtEOF() public void ParseBlockReportsErrorIfClassBlockUnterminatedAtEOF()
{ {
ParseBlockTest("functions { var foo = bar; if(foo != null) { bar(); } ", ParseBlockTest(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor), "functions { var foo = bar; if(foo != null) { bar(); } ",
new[] { FunctionsDirective.Directive, },
new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive),
Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),

View File

@ -2,7 +2,7 @@
// 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;
using System.Linq; using Microsoft.AspNetCore.Razor.Language.Extensions;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Razor.Language.Legacy namespace Microsoft.AspNetCore.Razor.Language.Legacy
@ -12,15 +12,17 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockCapturesNewlineImmediatelyFollowing() public void ParseSectionBlockCapturesNewlineImmediatelyFollowing()
{ {
ParseDocumentTest("@section" + Environment.NewLine, ParseDocumentTest(
"@section" + Environment.NewLine,
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None)), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None)),
Factory.Markup(Environment.NewLine)), Factory.Markup(Environment.NewLine)),
new RazorError( new RazorError(
LegacyResources.FormatDirectiveExpectsIdentifier(CSharpCodeParser.SectionDirectiveDescriptor.Directive), LegacyResources.FormatDirectiveExpectsIdentifier(SectionDirective.Directive.Directive),
new SourceLocation(8, 0, 8), new SourceLocation(8, 0, 8),
length: Environment.NewLine.Length)); length: Environment.NewLine.Length));
} }
@ -28,18 +30,20 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockCapturesWhitespaceToEndOfLineInSectionStatementMissingOpenBrace() public void ParseSectionBlockCapturesWhitespaceToEndOfLineInSectionStatementMissingOpenBrace()
{ {
ParseDocumentTest("@section Foo " + Environment.NewLine + " ", ParseDocumentTest(
"@section Foo " + Environment.NewLine + " ",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " " + Environment.NewLine + " ", markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace)), Factory.Span(SpanKindInternal.Markup, " " + Environment.NewLine + " ", markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace)),
Factory.EmptyHtml()), Factory.EmptyHtml()),
new RazorError( new RazorError(
LegacyResources.FormatUnexpectedEOFAfterDirective(CSharpCodeParser.SectionDirectiveDescriptor.Directive, "{"), LegacyResources.FormatUnexpectedEOFAfterDirective(SectionDirective.Directive.Directive, "{"),
new SourceLocation(25 + Environment.NewLine.Length, 0, 25 + Environment.NewLine.Length), new SourceLocation(25 + Environment.NewLine.Length, 0, 25 + Environment.NewLine.Length),
length: 1)); length: 1));
} }
@ -47,16 +51,18 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockCapturesWhitespaceToEndOfLineInSectionStatementMissingName() public void ParseSectionBlockCapturesWhitespaceToEndOfLineInSectionStatementMissingName()
{ {
ParseDocumentTest("@section " + Environment.NewLine + " ", ParseDocumentTest(
"@section " + Environment.NewLine + " ",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace)), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace)),
Factory.Markup(Environment.NewLine + " ")), Factory.Markup(Environment.NewLine + " ")),
new RazorError( new RazorError(
LegacyResources.FormatDirectiveExpectsIdentifier(CSharpCodeParser.SectionDirectiveDescriptor.Directive), LegacyResources.FormatDirectiveExpectsIdentifier(SectionDirective.Directive.Directive),
new SourceLocation(17, 0, 17), new SourceLocation(17, 0, 17),
length: Environment.NewLine.Length)); length: Environment.NewLine.Length));
} }
@ -64,7 +70,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockIgnoresSectionUnlessAllLowerCase() public void ParseSectionBlockIgnoresSectionUnlessAllLowerCase()
{ {
ParseDocumentTest("@Section foo", ParseDocumentTest(
"@Section foo",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new ExpressionBlock( new ExpressionBlock(
@ -78,10 +86,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockReportsErrorAndTerminatesSectionBlockIfKeywordNotFollowedByIdentifierStartCharacter() public void ParseSectionBlockReportsErrorAndTerminatesSectionBlockIfKeywordNotFollowedByIdentifierStartCharacter()
{ {
ParseDocumentTest("@section 9 { <p>Foo</p> }", ParseDocumentTest(
"@section 9 { <p>Foo</p> }",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace)), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace)),
@ -93,7 +103,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
Factory.Markup("</p>")), Factory.Markup("</p>")),
Factory.Markup(" }")), Factory.Markup(" }")),
new RazorError( new RazorError(
LegacyResources.FormatDirectiveExpectsIdentifier(CSharpCodeParser.SectionDirectiveDescriptor.Directive), LegacyResources.FormatDirectiveExpectsIdentifier(SectionDirective.Directive.Directive),
new SourceLocation(9, 0, 9), new SourceLocation(9, 0, 9),
length: 1)); length: 1));
} }
@ -101,14 +111,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockReportsErrorAndTerminatesSectionBlockIfNameNotFollowedByOpenBrace() public void ParseSectionBlockReportsErrorAndTerminatesSectionBlockIfNameNotFollowedByOpenBrace()
{ {
ParseDocumentTest("@section foo-bar { <p>Foo</p> }", ParseDocumentTest(
"@section foo-bar { <p>Foo</p> }",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0])), Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0])),
Factory.Markup("-bar { "), Factory.Markup("-bar { "),
new MarkupTagBlock( new MarkupTagBlock(
Factory.Markup("<p>")), Factory.Markup("<p>")),
@ -117,7 +129,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
Factory.Markup("</p>")), Factory.Markup("</p>")),
Factory.Markup(" }")), Factory.Markup(" }")),
new RazorError( new RazorError(
LegacyResources.FormatUnexpectedDirectiveLiteral(CSharpCodeParser.SectionDirectiveDescriptor.Directive, "{"), LegacyResources.FormatUnexpectedDirectiveLiteral(SectionDirective.Directive.Directive, "{"),
new SourceLocation(12, 0, 12), new SourceLocation(12, 0, 12),
length: 1)); length: 1));
} }
@ -125,23 +137,25 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParserOutputsErrorOnNestedSections() public void ParserOutputsErrorOnNestedSections()
{ {
ParseDocumentTest("@section foo { @section bar { <p>Foo</p> } }", ParseDocumentTest(
"@section foo { @section bar { <p>Foo</p> } }",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
Factory.Markup(" "), Factory.Markup(" "),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "bar", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "bar", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -169,20 +183,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockHandlesEOFAfterOpenBrace() public void ParseSectionBlockHandlesEOFAfterOpenBrace()
{ {
ParseDocumentTest("@section foo {", ParseDocumentTest(
"@section foo {",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml()))), Factory.EmptyHtml()))),
new RazorError( new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(CSharpCodeParser.SectionDirectiveDescriptor.Directive, "}", "{"), LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(SectionDirective.Directive.Directive, "}", "{"),
new SourceLocation(13, 0, 13), new SourceLocation(13, 0, 13),
length: 1)); length: 1));
} }
@ -194,14 +210,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[InlineData(" \n abc")] [InlineData(" \n abc")]
public void ParseSectionBlockHandlesEOFAfterOpenContent(string postStartBrace) public void ParseSectionBlockHandlesEOFAfterOpenContent(string postStartBrace)
{ {
ParseDocumentTest("@section foo {" + postStartBrace, ParseDocumentTest(
"@section foo {" + postStartBrace,
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -215,14 +233,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockHandlesUnterminatedSection() public void ParseSectionBlockHandlesUnterminatedSection()
{ {
ParseDocumentTest("@section foo { <p>Foo{}</p>", ParseDocumentTest(
"@section foo { <p>Foo{}</p>",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -249,13 +269,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"@section Test{0}{{{0}{1}@if(true){0}{1}{{{0}{1}{1}<p>Hello World</p>{0}{1}}}", "@section Test{0}{{{0}{1}@if(true){0}{1}{{{0}{1}{1}<p>Hello World</p>{0}{1}}}",
newLine, newLine,
spaces), spaces),
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "Test", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "Test", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, Environment.NewLine, CSharpSymbolType.NewLine).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, Environment.NewLine, CSharpSymbolType.NewLine).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -280,18 +301,20 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockReportsErrorAndAcceptsWhitespaceToEndOfLineIfSectionNotFollowedByOpenBrace() public void ParseSectionBlockReportsErrorAndAcceptsWhitespaceToEndOfLineIfSectionNotFollowedByOpenBrace()
{ {
ParseDocumentTest("@section foo " + Environment.NewLine, ParseDocumentTest(
"@section foo " + Environment.NewLine,
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " " + Environment.NewLine, markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace)), Factory.Span(SpanKindInternal.Markup, " " + Environment.NewLine, markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace)),
Factory.EmptyHtml()), Factory.EmptyHtml()),
new RazorError( new RazorError(
LegacyResources.FormatUnexpectedEOFAfterDirective(CSharpCodeParser.SectionDirectiveDescriptor.Directive, "{"), LegacyResources.FormatUnexpectedEOFAfterDirective(SectionDirective.Directive.Directive, "{"),
new SourceLocation(18 + Environment.NewLine.Length, 0, 18 + Environment.NewLine.Length), new SourceLocation(18 + Environment.NewLine.Length, 0, 18 + Environment.NewLine.Length),
length: 1)); length: 1));
} }
@ -308,13 +331,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
+ "{" + Environment.NewLine + "{" + Environment.NewLine
+ "<p>Foo</p>" + Environment.NewLine + "<p>Foo</p>" + Environment.NewLine
+ "}", + "}",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " " + string.Format("{0}{0}{0}{0}{0}{0}", Environment.NewLine), markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " " + string.Format("{0}{0}{0}{0}{0}{0}", Environment.NewLine), markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -332,14 +356,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockParsesNamedSectionCorrectly() public void ParseSectionBlockParsesNamedSectionCorrectly()
{ {
ParseDocumentTest("@section foo { <p>Foo</p> }", ParseDocumentTest(
"@section foo { <p>Foo</p> }",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -357,14 +383,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockDoesNotRequireSpaceBetweenSectionNameAndOpenBrace() public void ParseSectionBlockDoesNotRequireSpaceBetweenSectionNameAndOpenBrace()
{ {
ParseDocumentTest("@section foo{ <p>Foo</p> }", ParseDocumentTest(
"@section foo{ <p>Foo</p> }",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
Factory.Markup(" "), Factory.Markup(" "),
@ -381,14 +409,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockBalancesBraces() public void ParseSectionBlockBalancesBraces()
{ {
ParseDocumentTest("@section foo { <script>(function foo() { return 1; })();</script> }", ParseDocumentTest(
"@section foo { <script>(function foo() { return 1; })();</script> }",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -406,14 +436,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockAllowsBracesInCSharpExpression() public void ParseSectionBlockAllowsBracesInCSharpExpression()
{ {
ParseDocumentTest("@section foo { I really want to render a close brace, so here I go: @(\"}\") }", ParseDocumentTest(
"@section foo { I really want to render a close brace, so here I go: @(\"}\") }",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -435,13 +467,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
+ "@if(true) {" + Environment.NewLine + "@if(true) {" + Environment.NewLine
+ "}" + Environment.NewLine + "}" + Environment.NewLine
+ "}", + "}",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -460,13 +493,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
ParseDocumentTest("@section Foo {" + Environment.NewLine ParseDocumentTest("@section Foo {" + Environment.NewLine
+ "@if(true) {" + Environment.NewLine + "@if(true) {" + Environment.NewLine
+ "}}", + "}}",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -482,14 +516,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockCorrectlyTerminatesWhenCloseBraceImmediatelyFollowsMarkup() public void ParseSectionBlockCorrectlyTerminatesWhenCloseBraceImmediatelyFollowsMarkup()
{ {
ParseDocumentTest("@section foo {something}", ParseDocumentTest(
"@section foo {something}",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -501,14 +537,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockParsesComment() public void ParseSectionBlockParsesComment()
{ {
ParseDocumentTest("@section s {<!-- -->}", ParseDocumentTest(
"@section s {<!-- -->}",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -522,14 +560,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockParsesCommentWithDelimiters() public void ParseSectionBlockParsesCommentWithDelimiters()
{ {
ParseDocumentTest("@section s {<!-- > \" '-->}", ParseDocumentTest(
"@section s {<!-- > \" '-->}",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -543,13 +583,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
ParseDocumentTest( ParseDocumentTest(
"@section s {" + Environment.NewLine + "<a" + Environment.NewLine + "<!-- > \" '-->}", "@section s {" + Environment.NewLine + "<a" + Environment.NewLine + "<!-- > \" '-->}",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -566,13 +607,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
ParseDocumentTest( ParseDocumentTest(
"@section s { <? xml bleh ?>}", "@section s { <? xml bleh ?>}",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -593,11 +635,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"@section s {<span foo='@@' />}", "@section s {<span foo='@@' />}",
new MarkupBlock( new MarkupBlock(
factory.EmptyHtml(), factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
factory.CodeTransition(), factory.CodeTransition(),
factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
factory.Span(SpanKindInternal.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), factory.Span(SpanKindInternal.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -618,11 +660,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"@section s {<span foo='@DateTime.Now @@' />}", "@section s {<span foo='@DateTime.Now @@' />}",
new MarkupBlock( new MarkupBlock(
factory.EmptyHtml(), factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
factory.CodeTransition(), factory.CodeTransition(),
factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
factory.Span(SpanKindInternal.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), factory.Span(SpanKindInternal.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -656,7 +698,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
FixupSpans = true; FixupSpans = true;
ParseDocumentTest(input, (Block)expected); ParseDocumentTest(input, new[] { SectionDirective.Directive, }, (Block)expected);
} }
} }
} }

View File

@ -2,7 +2,7 @@
// 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;
using System.Linq; using Microsoft.AspNetCore.Razor.Language.Extensions;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Razor.Language.Legacy namespace Microsoft.AspNetCore.Razor.Language.Legacy
@ -12,32 +12,38 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseInheritsStatementMarksInheritsSpanAsCanGrowIfMissingTrailingSpace() public void ParseInheritsStatementMarksInheritsSpanAsCanGrowIfMissingTrailingSpace()
{ {
ParseBlockTest("inherits", ParseBlockTest(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), "inherits",
new[] { InheritsDirective.Directive, },
new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive),
Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None)), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None)),
new RazorError( new RazorError(
LegacyResources.FormatUnexpectedEOFAfterDirective(CSharpCodeParser.InheritsDirectiveDescriptor.Directive, "type"), LegacyResources.FormatUnexpectedEOFAfterDirective(InheritsDirective.Directive.Directive, "type"),
new SourceLocation(8, 0, 8), 1)); new SourceLocation(8, 0, 8), 1));
} }
[Fact] [Fact]
public void InheritsBlockAcceptsMultipleGenericArguments() public void InheritsBlockAcceptsMultipleGenericArguments()
{ {
ParseBlockTest("inherits Foo.Bar<Biz<Qux>, string, int>.Baz", ParseBlockTest(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), "inherits Foo.Bar<Biz<Qux>, string, int>.Baz",
new[] { InheritsDirective.Directive, },
new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive),
Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "Foo.Bar<Biz<Qux>, string, int>.Baz", markup: false).AsDirectiveToken(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens[0]))); Factory.Span(SpanKindInternal.Code, "Foo.Bar<Biz<Qux>, string, int>.Baz", markup: false).AsDirectiveToken(InheritsDirective.Directive.Tokens[0])));
} }
[Fact] [Fact]
public void InheritsBlockOutputsErrorIfInheritsNotFollowedByTypeButAcceptsEntireLineAsCode() public void InheritsBlockOutputsErrorIfInheritsNotFollowedByTypeButAcceptsEntireLineAsCode()
{ {
ParseBlockTest("inherits " + Environment.NewLine + "foo", ParseBlockTest(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), "inherits " + Environment.NewLine + "foo",
new[] { InheritsDirective.Directive, },
new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive),
Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace)), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace)),
new RazorError(LegacyResources.FormatDirectiveExpectsTypeName(CSharpCodeParser.InheritsDirectiveDescriptor.Directive), 24, 0, 24, Environment.NewLine.Length)); new RazorError(LegacyResources.FormatDirectiveExpectsTypeName(InheritsDirective.Directive.Directive), 24, 0, 24, Environment.NewLine.Length));
} }
[Fact] [Fact]
@ -138,8 +144,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
public void ParseBlockBalancesBracesAndOutputsContentAsClassLevelCodeSpanIfFirstIdentifierIsFunctionsKeyword() public void ParseBlockBalancesBracesAndOutputsContentAsClassLevelCodeSpanIfFirstIdentifierIsFunctionsKeyword()
{ {
const string code = " foo(); \"bar}baz\" "; const string code = " foo(); \"bar}baz\" ";
ParseBlockTest("functions {" + code + "} zoop", ParseBlockTest(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor), "functions {" + code + "} zoop",
new[] { FunctionsDirective.Directive, },
new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive),
Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
@ -150,8 +158,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseBlockDoesNoErrorRecoveryForFunctionsBlock() public void ParseBlockDoesNoErrorRecoveryForFunctionsBlock()
{ {
ParseBlockTest("functions { { { { { } zoop", ParseBlockTest(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor), "functions { { { { { } zoop",
new[] { FunctionsDirective.Directive, },
new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive),
Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),

View File

@ -9,9 +9,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
internal abstract ISet<string> KeywordSet { get; } internal abstract ISet<string> KeywordSet { get; }
internal override RazorSyntaxTree ParseBlock(string document, bool designTime) internal override RazorSyntaxTree ParseBlock(string document, IEnumerable<DirectiveDescriptor> directives, bool designTime)
{ {
return ParseCodeBlock(document, designTime); return ParseCodeBlock(document, directives, designTime);
} }
internal void ImplicitExpressionTest(string input, params RazorError[] errors) internal void ImplicitExpressionTest(string input, params RazorError[] errors)

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Razor.Language.Legacy namespace Microsoft.AspNetCore.Razor.Language.Legacy
@ -107,13 +108,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
ParseDocumentTest("@section Foo {" + Environment.NewLine ParseDocumentTest("@section Foo {" + Environment.NewLine
+ " <html></html>" + Environment.NewLine + " <html></html>" + Environment.NewLine
+ "}", + "}",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -469,14 +471,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionIgnoresTagsInContentsOfScriptTag() public void ParseSectionIgnoresTagsInContentsOfScriptTag()
{ {
ParseDocumentTest(@"@section Foo { <script>foo<bar baz='@boz'></script> }", ParseDocumentTest(
@"@section Foo { <script>foo<bar baz='@boz'></script> }",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Razor.Language.Legacy namespace Microsoft.AspNetCore.Razor.Language.Legacy
@ -281,7 +282,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void SectionContextGivesWhitespacePreceedingAtToCodeIfThereIsNoMarkupOnThatLine() public void SectionContextGivesWhitespacePreceedingAtToCodeIfThereIsNoMarkupOnThatLine()
{ {
var sectionDescriptor = CSharpCodeParser.SectionDirectiveDescriptor; var sectionDescriptor = SectionDirective.Directive;
ParseDocumentTest("@section foo {" + Environment.NewLine ParseDocumentTest("@section foo {" + Environment.NewLine
+ " <ul>" + Environment.NewLine + " <ul>" + Environment.NewLine
+ " @foreach(var p in Products) {" + Environment.NewLine + " @foreach(var p in Products) {" + Environment.NewLine
@ -289,13 +290,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
+ " }" + Environment.NewLine + " }" + Environment.NewLine
+ " </ul>" + Environment.NewLine + " </ul>" + Environment.NewLine
+ "}", + "}",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -389,14 +391,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void SectionBodyTreatsTwoAtSignsAsEscapeSequence() public void SectionBodyTreatsTwoAtSignsAsEscapeSequence()
{ {
ParseDocumentTest("@section Foo { <foo>@@bar</foo> }", ParseDocumentTest(
"@section Foo { <foo>@@bar</foo> }",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
@ -415,14 +419,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void SectionBodyTreatsPairsOfAtSignsAsEscapeSequence() public void SectionBodyTreatsPairsOfAtSignsAsEscapeSequence()
{ {
ParseDocumentTest("@section Foo { <foo>@@@@@bar</foo> }", ParseDocumentTest(
"@section Foo { <foo>@@@@@bar</foo> }",
new[] { SectionDirective.Directive, },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(

View File

@ -2,13 +2,15 @@
// 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.Collections.Generic;
namespace Microsoft.AspNetCore.Razor.Language.Legacy namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
public abstract class MarkupParserTestBase : CodeParserTestBase public abstract class MarkupParserTestBase : CodeParserTestBase
{ {
internal override RazorSyntaxTree ParseBlock(string document, bool designTime) internal override RazorSyntaxTree ParseBlock(string document, IEnumerable<DirectiveDescriptor> directives, bool designTime)
{ {
return ParseHtmlBlock(document, designTime); return ParseHtmlBlock(document, directives, designTime);
} }
internal virtual void SingleSpanDocumentTest(string document, BlockKindInternal blockKind, SpanKindInternal spanType) internal virtual void SingleSpanDocumentTest(string document, BlockKindInternal blockKind, SpanKindInternal spanType)

View File

@ -30,15 +30,27 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
internal BlockFactory BlockFactory { get; private set; } internal BlockFactory BlockFactory { get; private set; }
internal abstract RazorSyntaxTree ParseBlock(string document, bool designTime); internal RazorSyntaxTree ParseBlock(string document, bool designTime)
{
return ParseBlock(document, null, designTime);
}
internal abstract RazorSyntaxTree ParseBlock(string document, IEnumerable<DirectiveDescriptor> directives, bool designTime);
internal virtual RazorSyntaxTree ParseDocument(string document, bool designTime = false) internal virtual RazorSyntaxTree ParseDocument(string document, bool designTime = false)
{ {
return ParseDocument(document, null, designTime);
}
internal virtual RazorSyntaxTree ParseDocument(string document, IEnumerable<DirectiveDescriptor> directives, bool designTime = false)
{
directives = directives ?? Array.Empty<DirectiveDescriptor>();
var source = TestRazorSourceDocument.Create(document, fileName: null); var source = TestRazorSourceDocument.Create(document, fileName: null);
var options = RazorParserOptions.Create(Array.Empty<DirectiveDescriptor>(), designTime); var options = RazorParserOptions.Create(directives, designTime);
var context = new ParserContext(source, options); var context = new ParserContext(source, options);
var codeParser = new CSharpCodeParser(context); var codeParser = new CSharpCodeParser(directives, context);
var markupParser = new HtmlMarkupParser(context); var markupParser = new HtmlMarkupParser(context);
codeParser.HtmlParser = markupParser; codeParser.HtmlParser = markupParser;
@ -60,14 +72,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
return syntaxTree; return syntaxTree;
} }
internal virtual RazorSyntaxTree ParseHtmlBlock(string document, bool designTime = false) internal virtual RazorSyntaxTree ParseHtmlBlock(string document, IEnumerable<DirectiveDescriptor> directives, bool designTime = false)
{ {
directives = directives ?? Array.Empty<DirectiveDescriptor>();
var source = TestRazorSourceDocument.Create(document, fileName: null); var source = TestRazorSourceDocument.Create(document, fileName: null);
var options = RazorParserOptions.Create(Array.Empty<DirectiveDescriptor>(), designTime); var options = RazorParserOptions.Create(directives, designTime);
var context = new ParserContext(source, options); var context = new ParserContext(source, options);
var parser = new HtmlMarkupParser(context); var parser = new HtmlMarkupParser(context);
parser.CodeParser = new CSharpCodeParser(context) parser.CodeParser = new CSharpCodeParser(directives, context)
{ {
HtmlParser = parser, HtmlParser = parser,
}; };
@ -87,14 +101,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
internal virtual RazorSyntaxTree ParseCodeBlock( internal virtual RazorSyntaxTree ParseCodeBlock(
string document, string document,
IEnumerable<DirectiveDescriptor> descriptors, IEnumerable<DirectiveDescriptor> directives,
bool designTime) bool designTime)
{ {
directives = directives ?? Array.Empty<DirectiveDescriptor>();
var source = TestRazorSourceDocument.Create(document, fileName: null); var source = TestRazorSourceDocument.Create(document, fileName: null);
var options = RazorParserOptions.Create(descriptors, designTime); var options = RazorParserOptions.Create(directives, designTime);
var context = new ParserContext(source, options); var context = new ParserContext(source, options);
var parser = new CSharpCodeParser(descriptors, context); var parser = new CSharpCodeParser(directives, context);
parser.HtmlParser = new HtmlMarkupParser(context) parser.HtmlParser = new HtmlMarkupParser(context)
{ {
CodeParser = parser, CodeParser = parser,
@ -140,6 +156,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
ParseBlockTest(document, expectedRoot, false, null); ParseBlockTest(document, expectedRoot, false, null);
} }
internal virtual void ParseBlockTest(string document, IEnumerable<DirectiveDescriptor> directives, Block expectedRoot)
{
ParseBlockTest(document, directives, expectedRoot, false, null);
}
internal virtual void ParseBlockTest(string document, Block expectedRoot, bool designTime) internal virtual void ParseBlockTest(string document, Block expectedRoot, bool designTime)
{ {
ParseBlockTest(document, expectedRoot, designTime, null); ParseBlockTest(document, expectedRoot, designTime, null);
@ -150,9 +171,19 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
ParseBlockTest(document, expectedRoot, false, expectedErrors); ParseBlockTest(document, expectedRoot, false, expectedErrors);
} }
internal virtual void ParseBlockTest(string document, IEnumerable<DirectiveDescriptor> directives, Block expectedRoot, params RazorError[] expectedErrors)
{
ParseBlockTest(document, directives, expectedRoot, false, expectedErrors);
}
internal virtual void ParseBlockTest(string document, Block expected, bool designTime, params RazorError[] expectedErrors) internal virtual void ParseBlockTest(string document, Block expected, bool designTime, params RazorError[] expectedErrors)
{ {
var result = ParseBlock(document, designTime); ParseBlockTest(document, null, expected, designTime, expectedErrors);
}
internal virtual void ParseBlockTest(string document, IEnumerable<DirectiveDescriptor> directives, Block expected, bool designTime, params RazorError[] expectedErrors)
{
var result = ParseBlock(document, directives, designTime);
if (FixupSpans) if (FixupSpans)
{ {
@ -236,6 +267,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
ParseDocumentTest(document, expectedRoot, false, expectedErrors); ParseDocumentTest(document, expectedRoot, false, expectedErrors);
} }
internal virtual void ParseDocumentTest(string document, IEnumerable<DirectiveDescriptor> directives, Block expected, params RazorError[] expectedErrors)
{
ParseDocumentTest(document, directives, expected, false, expectedErrors);
}
internal virtual void ParseDocumentTest(string document, bool designTime) internal virtual void ParseDocumentTest(string document, bool designTime)
{ {
ParseDocumentTest(document, null, designTime); ParseDocumentTest(document, null, designTime);
@ -248,7 +284,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
internal virtual void ParseDocumentTest(string document, Block expected, bool designTime, params RazorError[] expectedErrors) internal virtual void ParseDocumentTest(string document, Block expected, bool designTime, params RazorError[] expectedErrors)
{ {
var result = ParseDocument(document, designTime); ParseDocumentTest(document, null, expected, designTime, expectedErrors);
}
internal virtual void ParseDocumentTest(string document, IEnumerable<DirectiveDescriptor> directives, Block expected, bool designTime, params RazorError[] expectedErrors)
{
var result = ParseDocument(document, directives, designTime);
if (FixupSpans) if (FixupSpans)
{ {

View File

@ -150,7 +150,6 @@ namespace Microsoft.AspNetCore.Razor.Language
feature => Assert.IsType<DefaultDirectiveSyntaxTreePass>(feature), feature => Assert.IsType<DefaultDirectiveSyntaxTreePass>(feature),
feature => Assert.IsType<HtmlNodeOptimizationPass>(feature), feature => Assert.IsType<HtmlNodeOptimizationPass>(feature),
feature => Assert.IsType<DefaultDocumentClassifierPass>(feature), feature => Assert.IsType<DefaultDocumentClassifierPass>(feature),
feature => Assert.IsType<DefaultDirectiveIRPass>(feature),
feature => Assert.IsType<DirectiveRemovalIROptimizationPass>(feature), feature => Assert.IsType<DirectiveRemovalIROptimizationPass>(feature),
feature => Assert.IsType<DefaultDocumentClassifierPassFeature>(feature), feature => Assert.IsType<DefaultDocumentClassifierPassFeature>(feature),
feature => Assert.IsType<RazorPreallocatedTagHelperAttributeOptimizationPass>(feature)); feature => Assert.IsType<RazorPreallocatedTagHelperAttributeOptimizationPass>(feature));
@ -179,7 +178,6 @@ namespace Microsoft.AspNetCore.Razor.Language
feature => Assert.IsType<DefaultDirectiveSyntaxTreePass>(feature), feature => Assert.IsType<DefaultDirectiveSyntaxTreePass>(feature),
feature => Assert.IsType<HtmlNodeOptimizationPass>(feature), feature => Assert.IsType<HtmlNodeOptimizationPass>(feature),
feature => Assert.IsType<DefaultDocumentClassifierPass>(feature), feature => Assert.IsType<DefaultDocumentClassifierPass>(feature),
feature => Assert.IsType<DefaultDirectiveIRPass>(feature),
feature => Assert.IsType<DirectiveRemovalIROptimizationPass>(feature), feature => Assert.IsType<DirectiveRemovalIROptimizationPass>(feature),
feature => Assert.IsType<DefaultDocumentClassifierPassFeature>(feature), feature => Assert.IsType<DefaultDocumentClassifierPassFeature>(feature),
feature => Assert.IsType<DesignTimeOptionsFeature>(feature), feature => Assert.IsType<DesignTimeOptionsFeature>(feature),