From 22d52f2a3c1be840c54eff478b58e5a4c53c7311 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Fri, 9 Jun 2017 18:13:44 -0700 Subject: [PATCH] Split the functions/section/inherits directives --- .../RazorExtensions.cs | 4 + .../DefaultDirectiveSyntaxTreePass.cs | 3 +- .../Extensions/FunctionsDirective.cs | 20 ++ .../Extensions/FunctionsDirectivePass.cs | 29 +++ .../Extensions/InheritsDirective.cs | 21 ++ .../Extensions/InheritsDirectivePass.cs | 34 +++ .../Extensions/SectionDirective.cs | 21 ++ .../SectionDirectivePass.cs} | 44 +--- .../Legacy/CSharpCodeParser.cs | 38 ++-- .../Legacy/ImplicitExpressionEditHandler.cs | 2 - .../RazorEngine.cs | 1 - .../ModelDirectiveTest.cs | 4 + .../DefaultDirectiveSyntaxTreePassTest.cs | 127 ------------ ...aultRazorIRLoweringPhaseIntegrationTest.cs | 3 + .../Extensions/FunctionsDirectivePassTest.cs | 103 ++++++++++ .../Extensions/InheritsDirectivePassTest.cs | 98 +++++++++ .../SectionDirectivePassTest.cs} | 129 ++++++------ .../Extensions/TemplateTargetExtensionTest.cs | 1 + .../CodeGenerationIntegrationTest.cs | 16 ++ .../Legacy/CSharpAutoCompleteTest.cs | 22 +- .../Legacy/CSharpDirectivesTest.cs | 59 ++++-- .../Legacy/CSharpErrorTest.cs | 7 +- .../Legacy/CSharpSectionTest.cs | 194 +++++++++++------- .../Legacy/CSharpSpecialBlockTest.cs | 38 ++-- .../Legacy/CodeParserTestBase.cs | 4 +- .../Legacy/HtmlDocumentTest.cs | 14 +- .../Legacy/HtmlToCodeSwitchTest.cs | 24 ++- .../Legacy/MarkupParserTestBase.cs | 6 +- .../Legacy/ParserTestBase.cs | 63 +++++- .../RazorEngineTest.cs | 2 - 30 files changed, 716 insertions(+), 415 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Razor.Language/Extensions/FunctionsDirective.cs create mode 100644 src/Microsoft.AspNetCore.Razor.Language/Extensions/FunctionsDirectivePass.cs create mode 100644 src/Microsoft.AspNetCore.Razor.Language/Extensions/InheritsDirective.cs create mode 100644 src/Microsoft.AspNetCore.Razor.Language/Extensions/InheritsDirectivePass.cs create mode 100644 src/Microsoft.AspNetCore.Razor.Language/Extensions/SectionDirective.cs rename src/Microsoft.AspNetCore.Razor.Language/{DefaultDirectiveIRPass.cs => Extensions/SectionDirectivePass.cs} (51%) delete mode 100644 test/Microsoft.AspNetCore.Razor.Language.Test/DefaultDirectiveSyntaxTreePassTest.cs create mode 100644 test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/FunctionsDirectivePassTest.cs create mode 100644 test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/InheritsDirectivePassTest.cs rename test/Microsoft.AspNetCore.Razor.Language.Test/{DefaultDirectiveIRPassTest.cs => Extensions/SectionDirectivePassTest.cs} (50%) diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/RazorExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/RazorExtensions.cs index ae701d3bcb..9b7d333b2e 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/RazorExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/RazorExtensions.cs @@ -15,6 +15,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions NamespaceDirective.Register(builder); PageDirective.Register(builder); + FunctionsDirective.Register(builder); + InheritsDirective.Register(builder); + SectionDirective.Register(builder); + builder.AddTargetExtension(new InjectDirectiveTargetExtension()); builder.AddTargetExtension(new TemplateTargetExtension() { diff --git a/src/Microsoft.AspNetCore.Razor.Language/DefaultDirectiveSyntaxTreePass.cs b/src/Microsoft.AspNetCore.Razor.Language/DefaultDirectiveSyntaxTreePass.cs index 11397495e1..d05949477c 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/DefaultDirectiveSyntaxTreePass.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/DefaultDirectiveSyntaxTreePass.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using Microsoft.AspNetCore.Razor.Language.Extensions; using Microsoft.AspNetCore.Razor.Language.Legacy; namespace Microsoft.AspNetCore.Razor.Language @@ -55,7 +56,7 @@ namespace Microsoft.AspNetCore.Razor.Language if (_nestedLevel > 0) { 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( directiveStart, LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS), diff --git a/src/Microsoft.AspNetCore.Razor.Language/Extensions/FunctionsDirective.cs b/src/Microsoft.AspNetCore.Razor.Language/Extensions/FunctionsDirective.cs new file mode 100644 index 0000000000..c752f5b53f --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/Extensions/FunctionsDirective.cs @@ -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()); + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Language/Extensions/FunctionsDirectivePass.cs b/src/Microsoft.AspNetCore.Razor.Language/Extensions/FunctionsDirectivePass.cs new file mode 100644 index 0000000000..012994ee50 --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/Extensions/FunctionsDirectivePass.cs @@ -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]); + } + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Language/Extensions/InheritsDirective.cs b/src/Microsoft.AspNetCore.Razor.Language/Extensions/InheritsDirective.cs new file mode 100644 index 0000000000..3ee9e0ac03 --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/Extensions/InheritsDirective.cs @@ -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()); + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Language/Extensions/InheritsDirectivePass.cs b/src/Microsoft.AspNetCore.Razor.Language/Extensions/InheritsDirectivePass.cs new file mode 100644 index 0000000000..79df4d146c --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/Extensions/InheritsDirectivePass.cs @@ -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; + } + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Language/Extensions/SectionDirective.cs b/src/Microsoft.AspNetCore.Razor.Language/Extensions/SectionDirective.cs new file mode 100644 index 0000000000..62facb074d --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/Extensions/SectionDirective.cs @@ -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()); + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Language/DefaultDirectiveIRPass.cs b/src/Microsoft.AspNetCore.Razor.Language/Extensions/SectionDirectivePass.cs similarity index 51% rename from src/Microsoft.AspNetCore.Razor.Language/DefaultDirectiveIRPass.cs rename to src/Microsoft.AspNetCore.Razor.Language/Extensions/SectionDirectivePass.cs index e55430dac6..f17fa570b0 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/DefaultDirectiveIRPass.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Extensions/SectionDirectivePass.cs @@ -1,53 +1,25 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; -using System.Collections.Generic; + using System.Linq; using 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) { - var parserOptions = irDocument.Options; - - var designTime = parserOptions.DesignTime; - - var classNode = irDocument.FindPrimaryClass(); - if (classNode == null) + var @class = irDocument.FindPrimaryClass(); + if (@class == null) { return; } - foreach (var functions in irDocument.FindDirectiveReferences(CSharpCodeParser.FunctionsDirectiveDescriptor)) + foreach (var section in irDocument.FindDirectiveReferences(SectionDirective.Directive)) { - functions.Remove(); - - 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 lambdaContent = irDocument.Options.DesignTime ? "__razor_section_writer" : string.Empty; var sectionName = ((DirectiveIRNode)section.Node).Tokens.FirstOrDefault()?.Content; var builder = RazorIRBuilder.Create(new CSharpCodeIRNode()); @@ -57,7 +29,7 @@ namespace Microsoft.AspNetCore.Razor.Language Content = $"DefineSection(\"{sectionName}\", async ({lambdaContent}) => {{" }); section.InsertBefore(builder.Build()); - + section.InsertBefore(section.Node.Children.Except(((DirectiveIRNode)section.Node).Tokens)); builder = RazorIRBuilder.Create(new CSharpCodeIRNode()); diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs b/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs index 33130bbb69..6d4d957b73 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs @@ -13,20 +13,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy private static readonly Func IsValidStatementSpacingSymbol = 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( SyntaxConstants.CSharp.AddTagHelperKeyword, DirectiveKind.SingleLine, @@ -42,11 +28,8 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy DirectiveKind.SingleLine, builder => builder.AddStringToken()); - internal static readonly IEnumerable DefaultDirectiveDescriptors = new[] + internal static readonly IEnumerable DefaultDirectiveDescriptors = new DirectiveDescriptor[] { - SectionDirectiveDescriptor, - FunctionsDirectiveDescriptor, - InheritsDirectiveDescriptor, }; internal static ISet DefaultKeywords = new HashSet() @@ -63,9 +46,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "switch", "lock", "using", - "section", - "inherits", - "functions", "namespace", "class", }; @@ -76,16 +56,26 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy private Dictionary> _keywordParsers = new Dictionary>(); public CSharpCodeParser(ParserContext context) - : this(directiveDescriptors: Enumerable.Empty(), context: context) + : this(directives: Enumerable.Empty(), context: context) { } - public CSharpCodeParser(IEnumerable directiveDescriptors, ParserContext context) + public CSharpCodeParser(IEnumerable directives, ParserContext 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(); SetUpKeywords(); - SetupDirectives(directiveDescriptors); + SetupDirectives(directives); SetUpExpressions(); } diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/ImplicitExpressionEditHandler.cs b/src/Microsoft.AspNetCore.Razor.Language/Legacy/ImplicitExpressionEditHandler.cs index 51d49bee66..82b9b5db19 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/ImplicitExpressionEditHandler.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Legacy/ImplicitExpressionEditHandler.cs @@ -47,7 +47,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { var other = obj as ImplicitExpressionEditHandler; return base.Equals(other) && - _keywords.SetEquals(other._keywords) && AcceptTrailingDot == other.AcceptTrailingDot; } @@ -55,7 +54,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { // Hash code should include only immutable properties and base has none. var hashCodeCombiner = HashCodeCombiner.Start(); - hashCodeCombiner.Add(Keywords); hashCodeCombiner.Add(AcceptTrailingDot); return hashCodeCombiner; diff --git a/src/Microsoft.AspNetCore.Razor.Language/RazorEngine.cs b/src/Microsoft.AspNetCore.Razor.Language/RazorEngine.cs index 93d624cde6..25781c98cf 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/RazorEngine.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/RazorEngine.cs @@ -70,7 +70,6 @@ namespace Microsoft.AspNetCore.Razor.Language // IR Passes builder.Features.Add(new DefaultDocumentClassifierPass()); - builder.Features.Add(new DefaultDirectiveIRPass()); builder.Features.Add(new DirectiveRemovalIROptimizationPass()); // Default Runtime Targets diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ModelDirectiveTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ModelDirectiveTest.cs index 0d4d8c9f5a..f2369e2cfe 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ModelDirectiveTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ModelDirectiveTest.cs @@ -5,6 +5,7 @@ using System; using System.IO; using System.Text; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.Language.Extensions; using Microsoft.AspNetCore.Razor.Language.Intermediate; 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. b.AddDirective(ModelDirective.Directive); + + // There's some special interaction with the inherits directive + InheritsDirective.Register(b); }); } diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultDirectiveSyntaxTreePassTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultDirectiveSyntaxTreePassTest.cs deleted file mode 100644 index 18d4286bed..0000000000 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultDirectiveSyntaxTreePassTest.cs +++ /dev/null @@ -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); - } - } -} diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorIRLoweringPhaseIntegrationTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorIRLoweringPhaseIntegrationTest.cs index 90e322782d..62a5394b5c 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorIRLoweringPhaseIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorIRLoweringPhaseIntegrationTest.cs @@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Razor.Language.Intermediate; using Xunit; using static Microsoft.AspNetCore.Razor.Language.Intermediate.RazorIRAssert; using Moq; +using Microsoft.AspNetCore.Razor.Language.Extensions; namespace Microsoft.AspNetCore.Razor.Language { @@ -459,6 +460,8 @@ namespace Microsoft.AspNetCore.Razor.Language { builder?.Invoke(b); + FunctionsDirective.Register(b); + SectionDirective.Register(b); b.AddTagHelpers(tagHelpers); }); diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/FunctionsDirectivePassTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/FunctionsDirectivePassTest.cs new file mode 100644 index 0000000000..1f3b0a541a --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/FunctionsDirectivePassTest.cs @@ -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(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(node), + node => Assert.IsType(node)); + + var @namespace = irDocument.Children[1]; + Children( + @namespace, + node => Assert.IsType(node)); + + var @class = @namespace.Children[0]; + Children( + @class, + node => Assert.IsType(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; + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/InheritsDirectivePassTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/InheritsDirectivePassTest.cs new file mode 100644 index 0000000000..3a153c43bc --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/InheritsDirectivePassTest.cs @@ -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"); + 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(node)); + } + + [Fact] + public void Execute_Inherits_SetsClassDeclarationBaseType() + { + // Arrange + var engine = CreateEngine(); + var pass = new InheritsDirectivePass() + { + Engine = engine, + }; + + var content = "@inherits Hello"; + 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(node), + node => Assert.IsType(node)); + + var @namespace = irDocument.Children[1]; + Children( + @namespace, + node => Assert.IsType(node)); + + var @class = (ClassDeclarationIRNode)@namespace.Children[0]; + Assert.Equal("Hello", @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; + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultDirectiveIRPassTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/SectionDirectivePassTest.cs similarity index 50% rename from test/Microsoft.AspNetCore.Razor.Language.Test/DefaultDirectiveIRPassTest.cs rename to test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/SectionDirectivePassTest.cs index d6e70419a5..24989b50ac 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultDirectiveIRPassTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/SectionDirectivePassTest.cs @@ -5,140 +5,127 @@ using Microsoft.AspNetCore.Razor.Language.Intermediate; using Xunit; 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] - public void Execute_Inherits_SetsClassDeclarationBaseType() + public void Execute_SkipsDocumentWithNoClassNode() { // Arrange - var content = "@inherits Hello"; - var sourceDocument = TestRazorSourceDocument.Create(content); - var codeDocument = RazorCodeDocument.Create(sourceDocument); - var irDocument = Lower(codeDocument); - var defaultEngine = RazorEngine.Create(); - var pass = new DefaultDirectiveIRPass() + var engine = CreateEngine(); + var pass = new SectionDirectivePass() { - Engine = defaultEngine, + Engine = engine, }; + var sourceDocument = TestRazorSourceDocument.Create("@section Header {

Hello World

}"); + var codeDocument = RazorCodeDocument.Create(sourceDocument); + + var irDocument = new DocumentIRNode(); + irDocument.Children.Add(new DirectiveIRNode() { Descriptor = SectionDirective.Directive, }); + // Act pass.Execute(codeDocument, irDocument); // Assert - Children(irDocument, - node => Assert.IsType(node), - node => Assert.IsType(node)); - var @namespace = irDocument.Children[1]; - Children(@namespace, - node => Assert.IsType(node)); - var @class = (ClassDeclarationIRNode)@namespace.Children[0]; - Assert.Equal("Hello", @class.BaseType); + Children( + irDocument, + node => Assert.IsType(node)); } [Fact] - public void Execute_Functions_MovesStatementToClassLevel() + public void Execute_WrapsStatementInDefineSection() { // Arrange - var content = "@functions { var value = true; }"; - var sourceDocument = TestRazorSourceDocument.Create(content); - var codeDocument = RazorCodeDocument.Create(sourceDocument); - var irDocument = Lower(codeDocument); - var defaultEngine = RazorEngine.Create(); - var pass = new DefaultDirectiveIRPass() + var engine = CreateEngine(); + var pass = new SectionDirectivePass() { - Engine = defaultEngine, + Engine = engine, }; - // Act - pass.Execute(codeDocument, irDocument); - - // Assert - Children(irDocument, - node => Assert.IsType(node), - node => Assert.IsType(node)); - var @namespace = irDocument.Children[1]; - Children(@namespace, - node => Assert.IsType(node)); - var @class = @namespace.Children[0]; - Children(@class, - node => Assert.IsType(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 {

Hello World

}"; var sourceDocument = TestRazorSourceDocument.Create(content); var codeDocument = RazorCodeDocument.Create(sourceDocument); - var irDocument = Lower(codeDocument); - var defaultEngine = RazorEngine.Create(); - var pass = new DefaultDirectiveIRPass() - { - Engine = defaultEngine, - }; + + var irDocument = Lower(codeDocument, engine); // Act pass.Execute(codeDocument, irDocument); // Assert - Children(irDocument, + Children( + irDocument, node => Assert.IsType(node), node => Assert.IsType(node)); + var @namespace = irDocument.Children[1]; - Children(@namespace, + Children( + @namespace, node => Assert.IsType(node)); + var @class = @namespace.Children[0]; var method = SingleChild(@class); - Children(method, + Children( + method, node => CSharpCode("DefineSection(\"Header\", async () => {", node), node => Html("

Hello World

", node), node => CSharpCode("});", node)); } [Fact] - public void Execute_Section_DesignTime_WrapsStatementInBackwardsCompatibleDefineSection() + public void Execute_DesignTime_WrapsStatementInBackwardsCompatibleDefineSection() { // Arrange + var engine = CreateDesignTimeEngine(); + var pass = new SectionDirectivePass() + { + Engine = engine, + }; + var content = "@section Header {

Hello World

}"; - var designTimeEngine = RazorEngine.CreateDesignTime(); var sourceDocument = TestRazorSourceDocument.Create(content); var codeDocument = RazorCodeDocument.Create(sourceDocument); - var irDocument = Lower(codeDocument, designTimeEngine); - var defaultEngine = RazorEngine.Create(); - var pass = new DefaultDirectiveIRPass() - { - Engine = defaultEngine, - }; + + var irDocument = Lower(codeDocument, engine); // Act pass.Execute(codeDocument, irDocument); // Assert - Children(irDocument, + Children( + irDocument, node => Assert.IsType(node), node => Assert.IsType(node)); + var @namespace = irDocument.Children[1]; - Children(@namespace, + Children( + @namespace, node => Assert.IsType(node)); + var @class = @namespace.Children[0]; var method = SingleChild(@class); - Children(method, + Children( + method, node => CSharpCode("DefineSection(\"Header\", async (__razor_section_writer) => {", node), node => Html("

Hello World

", 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) diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/TemplateTargetExtensionTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/TemplateTargetExtensionTest.cs index e74d2d1324..372b90f72d 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/TemplateTargetExtensionTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/TemplateTargetExtensionTest.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Razor.Language.CodeGeneration; using Microsoft.AspNetCore.Razor.Language.Legacy; using Xunit; +using static Microsoft.AspNetCore.Razor.Language.Intermediate.RazorIRAssert; namespace Microsoft.AspNetCore.Razor.Language.Extensions { diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/IntegrationTests/CodeGenerationIntegrationTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/IntegrationTests/CodeGenerationIntegrationTest.cs index 6a53ed64b5..8f384d1eac 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/IntegrationTests/CodeGenerationIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/IntegrationTests/CodeGenerationIntegrationTest.cs @@ -889,6 +889,10 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests // Some of these tests use templates builder.AddTargetExtension(new TemplateTargetExtension()); + + FunctionsDirective.Register(builder); + InheritsDirective.Register(builder); + SectionDirective.Register(builder); }); var document = CreateCodeDocument(); @@ -911,6 +915,10 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests // Some of these tests use templates builder.AddTargetExtension(new TemplateTargetExtension()); + + FunctionsDirective.Register(builder); + InheritsDirective.Register(builder); + SectionDirective.Register(builder); }); var document = CreateCodeDocument(); @@ -933,6 +941,10 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests // Some of these tests use templates builder.AddTargetExtension(new TemplateTargetExtension()); + + FunctionsDirective.Register(builder); + InheritsDirective.Register(builder); + SectionDirective.Register(builder); }); var document = CreateCodeDocument(); @@ -955,6 +967,10 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests // Some of these tests use templates builder.AddTargetExtension(new TemplateTargetExtension()); + + FunctionsDirective.Register(builder); + InheritsDirective.Register(builder); + SectionDirective.Register(builder); }); var document = CreateCodeDocument(); diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpAutoCompleteTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpAutoCompleteTest.cs index 604b863393..c5cd5ec692 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpAutoCompleteTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpAutoCompleteTest.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using Microsoft.AspNetCore.Razor.Language.Extensions; using Xunit; namespace Microsoft.AspNetCore.Razor.Language.Legacy @@ -14,12 +15,13 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { ParseBlockTest( "@functions{", - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor), + new[] { FunctionsDirective.Directive, }, + new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None)), 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), length: 1)); } @@ -28,12 +30,13 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy public void SectionDirectiveAutoCompleteAtEOF() { ParseBlockTest("@section Header {", - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new[] { SectionDirective.Directive, }, + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), 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.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -65,8 +68,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void FunctionsDirectiveAutoCompleteAtStartOfFile() { - ParseBlockTest("@functions{" + Environment.NewLine + "foo", - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor), + ParseBlockTest( + "@functions{" + Environment.NewLine + "foo", + new[] { FunctionsDirective.Directive, }, + new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("functions").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 + "

Foo

", - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new[] { SectionDirective.Directive, }, + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs index 69096be023..903ecd7033 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.AspNetCore.Razor.Language.Extensions; using Xunit; namespace Microsoft.AspNetCore.Razor.Language.Legacy @@ -987,56 +988,66 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy } [Fact] - public void InheritsDirective() + public void ParseBlock_InheritsDirective() { - ParseBlockTest("@inherits System.Web.WebPages.WebPage", - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), + ParseCodeBlockTest( + "@inherits System.Web.WebPages.WebPage", + new[] { InheritsDirective.Directive, }, + new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), 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] public void InheritsDirectiveSupportsArrays() { - ParseBlockTest("@inherits string[[]][]", - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), + ParseCodeBlockTest( + "@inherits string[[]][]", + new[] { InheritsDirective.Directive, }, + new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), 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] public void InheritsDirectiveSupportsNestedGenerics() { - ParseBlockTest("@inherits System.Web.Mvc.WebViewPage>", - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), + ParseCodeBlockTest( + "@inherits System.Web.Mvc.WebViewPage>", + new[] { InheritsDirective.Directive, }, + new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "System.Web.Mvc.WebViewPage>", markup: false) - .AsDirectiveToken(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))); + .AsDirectiveToken(InheritsDirective.Directive.Tokens.First()))); } [Fact] public void InheritsDirectiveSupportsTypeKeywords() { - ParseBlockTest("@inherits string", - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), + ParseCodeBlockTest( + "@inherits string", + new[] { InheritsDirective.Directive, }, + new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "string", markup: false) - .AsDirectiveToken(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))); + .AsDirectiveToken(InheritsDirective.Directive.Tokens.First()))); } [Fact] - public void FunctionsDirective() + public void Parse_FunctionsDirective() { - ParseBlockTest("@functions { foo(); bar(); }", - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor), + ParseCodeBlockTest( + "@functions { foo(); bar(); }", + new[] { FunctionsDirective.Directive, }, + new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), @@ -1048,8 +1059,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void EmptyFunctionsDirective() { - ParseBlockTest("@functions { }", - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor), + ParseCodeBlockTest( + "@functions { }", + new[] { FunctionsDirective.Directive, }, + new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), @@ -1059,15 +1072,17 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy } [Fact] - public void SectionDirective() + public void Parse_SectionDirective() { - ParseBlockTest("@section Header {

F{o}o

}", - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + ParseCodeBlockTest( + "@section Header {

F{o}o

}", + new[] { SectionDirective.Directive, }, + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpErrorTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpErrorTest.cs index c8c64a286e..e131008c6b 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpErrorTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpErrorTest.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using Microsoft.AspNetCore.Razor.Language.Extensions; using Xunit; namespace Microsoft.AspNetCore.Razor.Language.Legacy @@ -298,8 +299,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseBlockReportsErrorIfClassBlockUnterminatedAtEOF() { - ParseBlockTest("functions { var foo = bar; if(foo != null) { bar(); } ", - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor), + ParseBlockTest( + "functions { var foo = bar; if(foo != null) { bar(); } ", + new[] { FunctionsDirective.Directive, }, + new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSectionTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSectionTest.cs index 1d9fdd6aad..e4ccd83029 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSectionTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSectionTest.cs @@ -2,7 +2,7 @@ // 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.Extensions; using Xunit; namespace Microsoft.AspNetCore.Razor.Language.Legacy @@ -12,15 +12,17 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockCapturesNewlineImmediatelyFollowing() { - ParseDocumentTest("@section" + Environment.NewLine, + ParseDocumentTest( + "@section" + Environment.NewLine, + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None)), Factory.Markup(Environment.NewLine)), new RazorError( - LegacyResources.FormatDirectiveExpectsIdentifier(CSharpCodeParser.SectionDirectiveDescriptor.Directive), + LegacyResources.FormatDirectiveExpectsIdentifier(SectionDirective.Directive.Directive), new SourceLocation(8, 0, 8), length: Environment.NewLine.Length)); } @@ -28,18 +30,20 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockCapturesWhitespaceToEndOfLineInSectionStatementMissingOpenBrace() { - ParseDocumentTest("@section Foo " + Environment.NewLine + " ", + ParseDocumentTest( + "@section Foo " + Environment.NewLine + " ", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.EmptyHtml()), new RazorError( - LegacyResources.FormatUnexpectedEOFAfterDirective(CSharpCodeParser.SectionDirectiveDescriptor.Directive, "{"), + LegacyResources.FormatUnexpectedEOFAfterDirective(SectionDirective.Directive.Directive, "{"), new SourceLocation(25 + Environment.NewLine.Length, 0, 25 + Environment.NewLine.Length), length: 1)); } @@ -47,16 +51,18 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockCapturesWhitespaceToEndOfLineInSectionStatementMissingName() { - ParseDocumentTest("@section " + Environment.NewLine + " ", + ParseDocumentTest( + "@section " + Environment.NewLine + " ", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace)), Factory.Markup(Environment.NewLine + " ")), new RazorError( - LegacyResources.FormatDirectiveExpectsIdentifier(CSharpCodeParser.SectionDirectiveDescriptor.Directive), + LegacyResources.FormatDirectiveExpectsIdentifier(SectionDirective.Directive.Directive), new SourceLocation(17, 0, 17), length: Environment.NewLine.Length)); } @@ -64,7 +70,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockIgnoresSectionUnlessAllLowerCase() { - ParseDocumentTest("@Section foo", + ParseDocumentTest( + "@Section foo", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), new ExpressionBlock( @@ -78,10 +86,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockReportsErrorAndTerminatesSectionBlockIfKeywordNotFollowedByIdentifierStartCharacter() { - ParseDocumentTest("@section 9 {

Foo

}", + ParseDocumentTest( + "@section 9 {

Foo

}", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace)), @@ -93,7 +103,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.Markup("

")), Factory.Markup(" }")), new RazorError( - LegacyResources.FormatDirectiveExpectsIdentifier(CSharpCodeParser.SectionDirectiveDescriptor.Directive), + LegacyResources.FormatDirectiveExpectsIdentifier(SectionDirective.Directive.Directive), new SourceLocation(9, 0, 9), length: 1)); } @@ -101,14 +111,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockReportsErrorAndTerminatesSectionBlockIfNameNotFollowedByOpenBrace() { - ParseDocumentTest("@section foo-bar {

Foo

}", + ParseDocumentTest( + "@section foo-bar {

Foo

}", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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 { "), new MarkupTagBlock( Factory.Markup("

")), @@ -117,7 +129,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.Markup("

")), Factory.Markup(" }")), new RazorError( - LegacyResources.FormatUnexpectedDirectiveLiteral(CSharpCodeParser.SectionDirectiveDescriptor.Directive, "{"), + LegacyResources.FormatUnexpectedDirectiveLiteral(SectionDirective.Directive.Directive, "{"), new SourceLocation(12, 0, 12), length: 1)); } @@ -125,23 +137,25 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParserOutputsErrorOnNestedSections() { - ParseDocumentTest("@section foo { @section bar {

Foo

} }", + ParseDocumentTest( + "@section foo { @section bar {

Foo

} }", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( Factory.Markup(" "), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -169,20 +183,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockHandlesEOFAfterOpenBrace() { - ParseDocumentTest("@section foo {", + ParseDocumentTest( + "@section foo {", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( Factory.EmptyHtml()))), 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), length: 1)); } @@ -194,14 +210,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [InlineData(" \n abc")] public void ParseSectionBlockHandlesEOFAfterOpenContent(string postStartBrace) { - ParseDocumentTest("@section foo {" + postStartBrace, + ParseDocumentTest( + "@section foo {" + postStartBrace, + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -215,14 +233,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockHandlesUnterminatedSection() { - ParseDocumentTest("@section foo {

Foo{}

", + ParseDocumentTest( + "@section foo {

Foo{}

", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -249,13 +269,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "@section Test{0}{{{0}{1}@if(true){0}{1}{{{0}{1}{1}

Hello World

{0}{1}}}", newLine, spaces), + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -280,18 +301,20 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockReportsErrorAndAcceptsWhitespaceToEndOfLineIfSectionNotFollowedByOpenBrace() { - ParseDocumentTest("@section foo " + Environment.NewLine, + ParseDocumentTest( + "@section foo " + Environment.NewLine, + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.EmptyHtml()), new RazorError( - LegacyResources.FormatUnexpectedEOFAfterDirective(CSharpCodeParser.SectionDirectiveDescriptor.Directive, "{"), + LegacyResources.FormatUnexpectedEOFAfterDirective(SectionDirective.Directive.Directive, "{"), new SourceLocation(18 + Environment.NewLine.Length, 0, 18 + Environment.NewLine.Length), length: 1)); } @@ -308,13 +331,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy + "{" + Environment.NewLine + "

Foo

" + Environment.NewLine + "}", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -332,14 +356,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockParsesNamedSectionCorrectly() { - ParseDocumentTest("@section foo {

Foo

}", + ParseDocumentTest( + "@section foo {

Foo

}", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -357,14 +383,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockDoesNotRequireSpaceBetweenSectionNameAndOpenBrace() { - ParseDocumentTest("@section foo{

Foo

}", + ParseDocumentTest( + "@section foo{

Foo

}", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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), new MarkupBlock( Factory.Markup(" "), @@ -381,14 +409,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockBalancesBraces() { - ParseDocumentTest("@section foo { }", + ParseDocumentTest( + "@section foo { }", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -406,14 +436,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] 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( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -435,13 +467,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy + "@if(true) {" + Environment.NewLine + "}" + Environment.NewLine + "}", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -460,13 +493,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy ParseDocumentTest("@section Foo {" + Environment.NewLine + "@if(true) {" + Environment.NewLine + "}}", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -482,14 +516,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockCorrectlyTerminatesWhenCloseBraceImmediatelyFollowsMarkup() { - ParseDocumentTest("@section foo {something}", + ParseDocumentTest( + "@section foo {something}", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -501,14 +537,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockParsesComment() { - ParseDocumentTest("@section s {}", + ParseDocumentTest( + "@section s {}", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -522,14 +560,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockParsesCommentWithDelimiters() { - ParseDocumentTest("@section s {}", + ParseDocumentTest( + "@section s {}", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -543,13 +583,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { ParseDocumentTest( "@section s {" + Environment.NewLine + " \" '-->}", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -566,13 +607,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { ParseDocumentTest( "@section s { }", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -593,11 +635,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "@section s {}", new MarkupBlock( factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), factory.CodeTransition(), factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -618,11 +660,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "@section s {}", new MarkupBlock( factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), factory.CodeTransition(), factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -656,7 +698,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { FixupSpans = true; - ParseDocumentTest(input, (Block)expected); + ParseDocumentTest(input, new[] { SectionDirective.Directive, }, (Block)expected); } } } diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSpecialBlockTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSpecialBlockTest.cs index f9e2eea5ef..fbbfa9e2fc 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSpecialBlockTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSpecialBlockTest.cs @@ -2,7 +2,7 @@ // 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.Extensions; using Xunit; namespace Microsoft.AspNetCore.Razor.Language.Legacy @@ -12,32 +12,38 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseInheritsStatementMarksInheritsSpanAsCanGrowIfMissingTrailingSpace() { - ParseBlockTest("inherits", - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), + ParseBlockTest( + "inherits", + new[] { InheritsDirective.Directive, }, + new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None)), new RazorError( - LegacyResources.FormatUnexpectedEOFAfterDirective(CSharpCodeParser.InheritsDirectiveDescriptor.Directive, "type"), + LegacyResources.FormatUnexpectedEOFAfterDirective(InheritsDirective.Directive.Directive, "type"), new SourceLocation(8, 0, 8), 1)); } [Fact] public void InheritsBlockAcceptsMultipleGenericArguments() { - ParseBlockTest("inherits Foo.Bar, string, int>.Baz", - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), + ParseBlockTest( + "inherits Foo.Bar, string, int>.Baz", + new[] { InheritsDirective.Directive, }, + new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), - Factory.Span(SpanKindInternal.Code, "Foo.Bar, string, int>.Baz", markup: false).AsDirectiveToken(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens[0]))); + Factory.Span(SpanKindInternal.Code, "Foo.Bar, string, int>.Baz", markup: false).AsDirectiveToken(InheritsDirective.Directive.Tokens[0]))); } [Fact] public void InheritsBlockOutputsErrorIfInheritsNotFollowedByTypeButAcceptsEntireLineAsCode() { - ParseBlockTest("inherits " + Environment.NewLine + "foo", - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), + ParseBlockTest( + "inherits " + Environment.NewLine + "foo", + new[] { InheritsDirective.Directive, }, + new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), 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] @@ -138,8 +144,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy public void ParseBlockBalancesBracesAndOutputsContentAsClassLevelCodeSpanIfFirstIdentifierIsFunctionsKeyword() { const string code = " foo(); \"bar}baz\" "; - ParseBlockTest("functions {" + code + "} zoop", - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor), + ParseBlockTest( + "functions {" + code + "} zoop", + new[] { FunctionsDirective.Directive, }, + new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), @@ -150,8 +158,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseBlockDoesNoErrorRecoveryForFunctionsBlock() { - ParseBlockTest("functions { { { { { } zoop", - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor), + ParseBlockTest( + "functions { { { { { } zoop", + new[] { FunctionsDirective.Directive, }, + new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CodeParserTestBase.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CodeParserTestBase.cs index 8d04c156a0..f67b159189 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CodeParserTestBase.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CodeParserTestBase.cs @@ -9,9 +9,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { internal abstract ISet KeywordSet { get; } - internal override RazorSyntaxTree ParseBlock(string document, bool designTime) + internal override RazorSyntaxTree ParseBlock(string document, IEnumerable directives, bool designTime) { - return ParseCodeBlock(document, designTime); + return ParseCodeBlock(document, directives, designTime); } internal void ImplicitExpressionTest(string input, params RazorError[] errors) diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/HtmlDocumentTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/HtmlDocumentTest.cs index 890e83714d..b125b7523f 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/HtmlDocumentTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/HtmlDocumentTest.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using Microsoft.AspNetCore.Razor.Language.Extensions; using Xunit; namespace Microsoft.AspNetCore.Razor.Language.Legacy @@ -107,13 +108,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy ParseDocumentTest("@section Foo {" + Environment.NewLine + " " + Environment.NewLine + "}", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -469,14 +471,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionIgnoresTagsInContentsOfScriptTag() { - ParseDocumentTest(@"@section Foo { }", + ParseDocumentTest( + @"@section Foo { }", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/HtmlToCodeSwitchTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/HtmlToCodeSwitchTest.cs index a854d838b4..29c1dfb81a 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/HtmlToCodeSwitchTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/HtmlToCodeSwitchTest.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using Microsoft.AspNetCore.Razor.Language.Extensions; using Xunit; namespace Microsoft.AspNetCore.Razor.Language.Legacy @@ -281,7 +282,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void SectionContextGivesWhitespacePreceedingAtToCodeIfThereIsNoMarkupOnThatLine() { - var sectionDescriptor = CSharpCodeParser.SectionDirectiveDescriptor; + var sectionDescriptor = SectionDirective.Directive; ParseDocumentTest("@section foo {" + Environment.NewLine + "
    " + Environment.NewLine + " @foreach(var p in Products) {" + Environment.NewLine @@ -289,13 +290,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy + " }" + Environment.NewLine + "
" + Environment.NewLine + "}", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -389,14 +391,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void SectionBodyTreatsTwoAtSignsAsEscapeSequence() { - ParseDocumentTest("@section Foo { @@bar }", + ParseDocumentTest( + "@section Foo { @@bar }", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( @@ -415,14 +419,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void SectionBodyTreatsPairsOfAtSignsAsEscapeSequence() { - ParseDocumentTest("@section Foo { @@@@@bar }", + ParseDocumentTest( + "@section Foo { @@@@@bar }", + new[] { SectionDirective.Directive, }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), + new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), 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.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/MarkupParserTestBase.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/MarkupParserTestBase.cs index b4a0d1c00b..096681ed4c 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/MarkupParserTestBase.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/MarkupParserTestBase.cs @@ -2,13 +2,15 @@ // 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 { public abstract class MarkupParserTestBase : CodeParserTestBase { - internal override RazorSyntaxTree ParseBlock(string document, bool designTime) + internal override RazorSyntaxTree ParseBlock(string document, IEnumerable directives, bool designTime) { - return ParseHtmlBlock(document, designTime); + return ParseHtmlBlock(document, directives, designTime); } internal virtual void SingleSpanDocumentTest(string document, BlockKindInternal blockKind, SpanKindInternal spanType) diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/ParserTestBase.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/ParserTestBase.cs index 4b1cf56d78..7fc8687cc3 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/ParserTestBase.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/ParserTestBase.cs @@ -30,15 +30,27 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy 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 directives, bool designTime); internal virtual RazorSyntaxTree ParseDocument(string document, bool designTime = false) { + return ParseDocument(document, null, designTime); + } + + internal virtual RazorSyntaxTree ParseDocument(string document, IEnumerable directives, bool designTime = false) + { + directives = directives ?? Array.Empty(); + var source = TestRazorSourceDocument.Create(document, fileName: null); - var options = RazorParserOptions.Create(Array.Empty(), designTime); + var options = RazorParserOptions.Create(directives, designTime); var context = new ParserContext(source, options); - var codeParser = new CSharpCodeParser(context); + var codeParser = new CSharpCodeParser(directives, context); var markupParser = new HtmlMarkupParser(context); codeParser.HtmlParser = markupParser; @@ -60,14 +72,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy return syntaxTree; } - internal virtual RazorSyntaxTree ParseHtmlBlock(string document, bool designTime = false) + internal virtual RazorSyntaxTree ParseHtmlBlock(string document, IEnumerable directives, bool designTime = false) { + directives = directives ?? Array.Empty(); + var source = TestRazorSourceDocument.Create(document, fileName: null); - var options = RazorParserOptions.Create(Array.Empty(), designTime); + var options = RazorParserOptions.Create(directives, designTime); var context = new ParserContext(source, options); var parser = new HtmlMarkupParser(context); - parser.CodeParser = new CSharpCodeParser(context) + parser.CodeParser = new CSharpCodeParser(directives, context) { HtmlParser = parser, }; @@ -87,14 +101,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy internal virtual RazorSyntaxTree ParseCodeBlock( string document, - IEnumerable descriptors, + IEnumerable directives, bool designTime) { + directives = directives ?? Array.Empty(); + 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 parser = new CSharpCodeParser(descriptors, context); + var parser = new CSharpCodeParser(directives, context); parser.HtmlParser = new HtmlMarkupParser(context) { CodeParser = parser, @@ -140,6 +156,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy ParseBlockTest(document, expectedRoot, false, null); } + internal virtual void ParseBlockTest(string document, IEnumerable directives, Block expectedRoot) + { + ParseBlockTest(document, directives, expectedRoot, false, null); + } + internal virtual void ParseBlockTest(string document, Block expectedRoot, bool designTime) { ParseBlockTest(document, expectedRoot, designTime, null); @@ -150,9 +171,19 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy ParseBlockTest(document, expectedRoot, false, expectedErrors); } + internal virtual void ParseBlockTest(string document, IEnumerable 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) { - var result = ParseBlock(document, designTime); + ParseBlockTest(document, null, expected, designTime, expectedErrors); + } + + internal virtual void ParseBlockTest(string document, IEnumerable directives, Block expected, bool designTime, params RazorError[] expectedErrors) + { + var result = ParseBlock(document, directives, designTime); if (FixupSpans) { @@ -236,6 +267,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy ParseDocumentTest(document, expectedRoot, false, expectedErrors); } + internal virtual void ParseDocumentTest(string document, IEnumerable directives, Block expected, params RazorError[] expectedErrors) + { + ParseDocumentTest(document, directives, expected, false, expectedErrors); + } + internal virtual void ParseDocumentTest(string document, bool 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) { - var result = ParseDocument(document, designTime); + ParseDocumentTest(document, null, expected, designTime, expectedErrors); + } + + internal virtual void ParseDocumentTest(string document, IEnumerable directives, Block expected, bool designTime, params RazorError[] expectedErrors) + { + var result = ParseDocument(document, directives, designTime); if (FixupSpans) { diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/RazorEngineTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/RazorEngineTest.cs index 25e7d9f90a..0ea1f5689a 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/RazorEngineTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/RazorEngineTest.cs @@ -150,7 +150,6 @@ namespace Microsoft.AspNetCore.Razor.Language feature => Assert.IsType(feature), feature => Assert.IsType(feature), feature => Assert.IsType(feature), - feature => Assert.IsType(feature), feature => Assert.IsType(feature), feature => Assert.IsType(feature), feature => Assert.IsType(feature)); @@ -179,7 +178,6 @@ namespace Microsoft.AspNetCore.Razor.Language feature => Assert.IsType(feature), feature => Assert.IsType(feature), feature => Assert.IsType(feature), - feature => Assert.IsType(feature), feature => Assert.IsType(feature), feature => Assert.IsType(feature), feature => Assert.IsType(feature),