Modify functions, section and inherits to use extensible directives.

- Removed existing type names used to track `@functions`, `@section` and `@inherits`.
- Updated parsing logic to reflect existing directive behaviors.
- Added additional IR and syntax tree pass in order to fulfill the default directive expectations.
- Updated tests to to expect new extensible directives parse structure.

#894
This commit is contained in:
N. Taylor Mullen 2016-12-12 17:27:14 -08:00
parent 1b3863044d
commit 2db4985c21
27 changed files with 836 additions and 648 deletions

View File

@ -0,0 +1,61 @@
// 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.Evolution.Intermediate;
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
namespace Microsoft.AspNetCore.Razor.Evolution
{
internal class DefaultDirectiveIRPass : IRazorIRPass
{
public RazorEngine Engine { get; set; }
public int Order => 150;
public DocumentIRNode Execute(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
{
var walker = new DirectiveWalker();
walker.VisitDefault(irDocument);
return irDocument;
}
private class DirectiveWalker : RazorIRNodeWalker
{
private ClassDeclarationIRNode _classNode;
public override void VisitClass(ClassDeclarationIRNode node)
{
if (_classNode == null)
{
_classNode = node;
}
VisitDefault(node);
}
public override void VisitDirective(DirectiveIRNode node)
{
if (string.Equals(node.Name, CSharpCodeParser.FunctionsDirectiveDescriptor.Name, StringComparison.Ordinal))
{
foreach (var child in node.Children.Except(node.Tokens))
{
child.Parent = _classNode;
_classNode.Children.Add(child);
}
}
else if (string.Equals(node.Name, CSharpCodeParser.InheritsDirectiveDescriptor.Name, StringComparison.Ordinal))
{
var token = node.Tokens.FirstOrDefault();
if (token != null)
{
_classNode.BaseType = token.Content;
}
}
}
}
}
}

View File

@ -0,0 +1,62 @@
// 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.Evolution.Legacy;
namespace Microsoft.AspNetCore.Razor.Evolution
{
internal class DefaultDirectiveSyntaxTreePass : IRazorSyntaxTreePass
{
public RazorEngine Engine { get; set; }
public int Order => 75;
public RazorSyntaxTree Execute(RazorCodeDocument codeDocument, RazorSyntaxTree syntaxTree)
{
var errorSink = new ErrorSink();
var sectionVerifier = new NestedSectionVerifier();
sectionVerifier.Verify(syntaxTree, errorSink);
if (errorSink.Errors.Count > 0)
{
var combinedErrors = syntaxTree.Diagnostics.Concat(errorSink.Errors).ToList();
syntaxTree = RazorSyntaxTree.Create(syntaxTree.Root, combinedErrors, syntaxTree.Options);
}
return syntaxTree;
}
private class NestedSectionVerifier : ParserVisitor
{
private int _nestedLevel;
private ErrorSink _errorSink;
public void Verify(RazorSyntaxTree tree, ErrorSink errorSink)
{
_errorSink = errorSink;
tree.Root.Accept(this);
}
public override void VisitStartDirectiveBlock(DirectiveChunkGenerator chunkGenerator, Block block)
{
if (_nestedLevel > 0)
{
var directiveStart = block.Children.First(child => !child.IsBlock && ((Span)child).Kind == SpanKind.Transition).Start;
var errorLength = /* @ */ 1 + CSharpCodeParser.SectionDirectiveDescriptor.Name.Length;
_errorSink.OnError(
directiveStart,
LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS),
errorLength);
}
_nestedLevel++;
}
public override void VisitEndDirectiveBlock(DirectiveChunkGenerator chunkGenerator, Block block)
{
_nestedLevel--;
}
}
}
}

View File

@ -153,18 +153,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution
});
}
public override void VisitTypeMemberSpan(TypeMemberChunkGenerator chunkGenerator, Span span)
{
var functionsNode = new CSharpStatementIRNode()
{
Content = span.Content,
SourceRange = new MappingLocation(span.Start, span.Length),
Parent = Class,
};
Class.Children.Add(functionsNode);
}
public override void VisitStatementSpan(StatementChunkGenerator chunkGenerator, Span span)
{
Builder.Add(new CSharpStatementIRNode()

View File

@ -14,6 +14,30 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
private static readonly Func<CSharpSymbol, bool> IsValidStatementSpacingSymbol =
IsSpacingToken(includeNewLines: true, includeComments: true);
internal static readonly DirectiveDescriptor SectionDirectiveDescriptor =
DirectiveDescriptorBuilder
.CreateRazorBlock(SyntaxConstants.CSharp.SectionKeyword)
.AddMember()
.Build();
internal static readonly DirectiveDescriptor FunctionsDirectiveDescriptor =
DirectiveDescriptorBuilder
.CreateCodeBlock(SyntaxConstants.CSharp.FunctionsKeyword)
.Build();
internal static readonly DirectiveDescriptor InheritsDirectiveDescriptor =
DirectiveDescriptorBuilder
.Create(SyntaxConstants.CSharp.InheritsKeyword)
.AddType()
.Build();
internal static readonly IEnumerable<DirectiveDescriptor> DefaultDirectiveDescriptors = new[]
{
SectionDirectiveDescriptor,
FunctionsDirectiveDescriptor,
InheritsDirectiveDescriptor,
};
internal static ISet<string> DefaultKeywords = new HashSet<string>()
{
SyntaxConstants.CSharp.TagHelperPrefixKeyword,
@ -35,6 +59,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
"class",
};
private readonly ISet<string> CurrentKeywords = new HashSet<string>(DefaultKeywords);
private Dictionary<string, Action> _directiveParsers = new Dictionary<string, Action>(StringComparer.Ordinal);
private Dictionary<CSharpKeyword, Action<bool>> _keywordParsers = new Dictionary<CSharpKeyword, Action<bool>>();
@ -263,7 +289,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
Span.ChunkGenerator = new ExpressionChunkGenerator();
Span.EditHandler = new ImplicitExpressionEditHandler(
Language.TokenizeString,
DefaultKeywords,
CurrentKeywords,
acceptTrailingDot: IsNested)
{
AcceptedCharacters = AcceptedCharacters.NonWhiteSpace
@ -611,7 +637,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
private void SectionBlock(string left, string right, bool caseSensitive)
{
ParseWithOtherParser(p => p.ParseSection(Tuple.Create(left, right), caseSensitive));
ParseWithOtherParser(p => p.ParseRazorBlock(Tuple.Create(left, right), caseSensitive));
}
private void NestedBlock()
@ -1411,17 +1437,18 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
private void SetupDirectives(IEnumerable<DirectiveDescriptor> directiveDescriptors)
{
foreach (var directiveDescriptor in directiveDescriptors)
var allDirectives = directiveDescriptors.Concat(DefaultDirectiveDescriptors).ToList();
for (var i = 0; i < allDirectives.Count; i++)
{
var directiveDescriptor = allDirectives[i];
CurrentKeywords.Add(directiveDescriptor.Name);
MapDirectives(() => HandleDirective(directiveDescriptor), directiveDescriptor.Name);
}
MapDirectives(TagHelperPrefixDirective, SyntaxConstants.CSharp.TagHelperPrefixKeyword);
MapDirectives(AddTagHelperDirective, SyntaxConstants.CSharp.AddTagHelperKeyword);
MapDirectives(RemoveTagHelperDirective, SyntaxConstants.CSharp.RemoveTagHelperKeyword);
MapDirectives(InheritsDirective, SyntaxConstants.CSharp.InheritsKeyword);
MapDirectives(FunctionsDirective, SyntaxConstants.CSharp.FunctionsKeyword);
MapDirectives(SectionDirective, SyntaxConstants.CSharp.SectionKeyword);
}
private void HandleDirective(DirectiveDescriptor descriptor)
@ -1449,14 +1476,27 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
Output(SpanKind.Markup, AcceptedCharacters.WhiteSpace);
}
if (EndOfFile)
{
Context.ErrorSink.OnError(
CurrentLocation,
LegacyResources.FormatUnexpectedEOFAfterDirective(descriptor.Name, tokenDescriptor.Kind.ToString().ToLowerInvariant()),
length: 1);
return;
}
var outputKind = SpanKind.Markup;
switch (tokenDescriptor.Kind)
{
case DirectiveTokenKind.Type:
if (!NamespaceOrTypeName())
{
// Error logged for invalid type name, continue onto next piece.
continue;
Context.ErrorSink.OnError(
CurrentLocation,
LegacyResources.FormatDirectiveExpectsTypeName(descriptor.Name),
CurrentSymbol.Content.Length);
return;
}
outputKind = SpanKind.Code;
@ -1520,10 +1560,11 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
CurrentSymbol.Content.Length);
}
Output(SpanKind.Markup, AcceptedCharacters.AllWhiteSpace);
Output(SpanKind.Markup, AcceptedCharacters.WhiteSpace);
break;
case DirectiveDescriptorKind.RazorBlock:
Output(SpanKind.Markup, AcceptedCharacters.WhiteSpace);
AcceptWhile(IsSpacingToken(includeNewLines: true, includeComments: true));
Output(SpanKind.Markup, AcceptedCharacters.AllWhiteSpace);
ParseDirectiveBlock(descriptor, parseChildren: (startingBraceLocation) =>
{
@ -1534,7 +1575,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
IsNested = false;
using (PushSpanConfig())
{
HtmlParser.ParseSection(Tuple.Create("{", "}"), caseSensitive: true);
HtmlParser.ParseRazorBlock(Tuple.Create("{", "}"), caseSensitive: true);
}
Initialize(Span);
IsNested = wasNested;
@ -1542,7 +1583,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
});
break;
case DirectiveDescriptorKind.CodeBlock:
Output(SpanKind.Markup, AcceptedCharacters.WhiteSpace);
AcceptWhile(IsSpacingToken(includeNewLines: true, includeComments: true));
Output(SpanKind.Markup, AcceptedCharacters.AllWhiteSpace);
ParseDirectiveBlock(descriptor, parseChildren: (startingBraceLocation) =>
{
@ -1588,7 +1630,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
editHandler.AutoCompleteString = "}";
Context.ErrorSink.OnError(
startingBraceLocation,
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(descriptor.Name, "{", "}"),
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(descriptor.Name, "}", "{"),
length: 1 /* } */);
}
else
@ -1622,186 +1664,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
lookupText => new RemoveTagHelperChunkGenerator(lookupText));
}
protected virtual void SectionDirective()
{
var nested = Context.Builder.ActiveBlocks.Any(block => block.Type == BlockType.Section);
var errorReported = false;
// Set the block and span type
Context.Builder.CurrentBlock.Type = BlockType.Section;
// Verify we're on "section" and accept
AssertDirective(SyntaxConstants.CSharp.SectionKeyword);
var startLocation = CurrentLocation;
AcceptAndMoveNext();
if (nested)
{
Context.ErrorSink.OnError(
startLocation,
LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS),
Span.GetContent().Value.Length);
errorReported = true;
}
var whitespace = ReadWhile(IsSpacingToken(includeNewLines: true, includeComments: false));
// Get the section name
var sectionName = string.Empty;
if (!Required(CSharpSymbolType.Identifier,
errorIfNotFound: true,
errorBase: LegacyResources.FormatParseError_Unexpected_Character_At_Section_Name_Start))
{
if (!errorReported)
{
errorReported = true;
}
PutCurrentBack();
PutBack(whitespace);
AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: false));
}
else
{
Accept(whitespace);
sectionName = CurrentSymbol.Content;
AcceptAndMoveNext();
}
Context.Builder.CurrentBlock.ChunkGenerator = new SectionChunkGenerator(sectionName);
var errorLocation = CurrentLocation;
whitespace = ReadWhile(IsSpacingToken(includeNewLines: true, includeComments: false));
// Get the starting brace
var sawStartingBrace = At(CSharpSymbolType.LeftBrace);
if (!sawStartingBrace)
{
if (!errorReported)
{
errorReported = true;
Context.ErrorSink.OnError(
errorLocation,
LegacyResources.ParseError_MissingOpenBraceAfterSection,
length: 1 /* { */);
}
PutCurrentBack();
PutBack(whitespace);
AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: false));
Optional(CSharpSymbolType.NewLine);
Output(SpanKind.MetaCode);
CompleteBlock();
return;
}
else
{
Accept(whitespace);
}
var startingBraceLocation = CurrentLocation;
// Set up edit handler
var editHandler = new AutoCompleteEditHandler(Language.TokenizeString, autoCompleteAtEndOfSpan: true);
Span.EditHandler = editHandler;
Span.Accept(CurrentSymbol);
// Output Metacode then switch to section parser
Output(SpanKind.MetaCode);
SectionBlock("{", "}", caseSensitive: true);
Span.ChunkGenerator = SpanChunkGenerator.Null;
// Check for the terminating "}"
if (!Optional(CSharpSymbolType.RightBrace))
{
editHandler.AutoCompleteString = "}";
Context.ErrorSink.OnError(
startingBraceLocation,
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(
SyntaxConstants.CSharp.SectionKeyword,
Language.GetSample(CSharpSymbolType.RightBrace),
Language.GetSample(CSharpSymbolType.LeftBrace)),
length: 1 /* } */);
}
else
{
Span.EditHandler.AcceptedCharacters = AcceptedCharacters.None;
}
CompleteBlock(insertMarkerIfNecessary: false, captureWhitespaceToEndOfLine: true);
Output(SpanKind.MetaCode);
return;
}
protected virtual void FunctionsDirective()
{
// Set the block type
Context.Builder.CurrentBlock.Type = BlockType.Functions;
// Verify we're on "functions" and accept
AssertDirective(SyntaxConstants.CSharp.FunctionsKeyword);
var block = new Block(CurrentSymbol);
AcceptAndMoveNext();
AcceptWhile(IsSpacingToken(includeNewLines: true, includeComments: false));
if (!At(CSharpSymbolType.LeftBrace))
{
Context.ErrorSink.OnError(
CurrentLocation,
LegacyResources.FormatParseError_Expected_X(Language.GetSample(CSharpSymbolType.LeftBrace)),
length: 1 /* { */);
CompleteBlock();
Output(SpanKind.MetaCode);
return;
}
else
{
Span.EditHandler.AcceptedCharacters = AcceptedCharacters.None;
}
// Capture start point and continue
var blockStart = CurrentLocation;
AcceptAndMoveNext();
// Output what we've seen and continue
Output(SpanKind.MetaCode);
var editHandler = new AutoCompleteEditHandler(Language.TokenizeString);
Span.EditHandler = editHandler;
Balance(BalancingModes.NoErrorOnFailure, CSharpSymbolType.LeftBrace, CSharpSymbolType.RightBrace, blockStart);
Span.ChunkGenerator = new TypeMemberChunkGenerator();
if (!At(CSharpSymbolType.RightBrace))
{
editHandler.AutoCompleteString = "}";
Context.ErrorSink.OnError(
blockStart,
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(block.Name, "}", "{"),
length: 1 /* } */);
CompleteBlock();
Output(SpanKind.Code);
}
else
{
Output(SpanKind.Code);
Assert(CSharpSymbolType.RightBrace);
Span.ChunkGenerator = SpanChunkGenerator.Null;
Span.EditHandler.AcceptedCharacters = AcceptedCharacters.None;
AcceptAndMoveNext();
CompleteBlock();
Output(SpanKind.MetaCode);
}
}
protected virtual void InheritsDirective()
{
// Verify we're on the right keyword and accept
AssertDirective(SyntaxConstants.CSharp.InheritsKeyword);
AcceptAndMoveNext();
InheritsDirectiveCore();
}
[Conditional("DEBUG")]
protected void AssertDirective(string directive)
{
@ -1809,13 +1671,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
Debug.Assert(string.Equals(CurrentSymbol.Content, directive, StringComparison.Ordinal));
}
protected void InheritsDirectiveCore()
{
BaseTypeDirective(
LegacyResources.ParseError_InheritsKeyword_Must_Be_Followed_By_TypeName,
baseType => new SetBaseTypeChunkGenerator(baseType));
}
protected void BaseTypeDirective(string noTypeNameError, Func<string, SpanChunkGenerator> createChunkGenerator)
{
var keywordStartLocation = Span.Start;

View File

@ -1577,7 +1577,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
return false;
}
public void ParseSection(Tuple<string, string> nestingSequences, bool caseSensitive)
public void ParseRazorBlock(Tuple<string, string> nestingSequences, bool caseSensitive)
{
if (Context == null)
{

View File

@ -69,10 +69,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{
}
public virtual void VisitTypeMemberSpan(TypeMemberChunkGenerator chunkGenerator, Span span)
{
}
public virtual void VisitMarkupSpan(MarkupChunkGenerator chunkGenerator, Span span)
{
}

View File

@ -1,54 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{
internal class SectionChunkGenerator : ParentChunkGenerator
{
public SectionChunkGenerator(string sectionName)
{
SectionName = sectionName;
}
public string SectionName { get; }
public override void AcceptStart(ParserVisitor visitor, Block block)
{
}
public override void AcceptEnd(ParserVisitor visitor, Block block)
{
}
public override void GenerateStartParentChunk(Block target, ChunkGeneratorContext context)
{
//var chunk = context.ChunkTreeBuilder.StartParentChunk<SectionChunk>(target);
//chunk.Name = SectionName;
}
public override void GenerateEndParentChunk(Block target, ChunkGeneratorContext context)
{
//context.ChunkTreeBuilder.EndParentChunk();
}
public override bool Equals(object obj)
{
var other = obj as SectionChunkGenerator;
return base.Equals(other) &&
string.Equals(SectionName, other.SectionName, StringComparison.Ordinal);
}
public override int GetHashCode()
{
return SectionName == null ? 0 : StringComparer.Ordinal.GetHashCode(SectionName);
}
public override string ToString()
{
return "Section:" + SectionName;
}
}
}

View File

@ -1,42 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{
internal class SetBaseTypeChunkGenerator : SpanChunkGenerator
{
public SetBaseTypeChunkGenerator(string baseType)
{
BaseType = baseType;
}
public string BaseType { get; }
public override void Accept(ParserVisitor visitor, Span span)
{
}
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
{
}
public override string ToString()
{
return "Base:" + BaseType;
}
public override bool Equals(object obj)
{
var other = obj as SetBaseTypeChunkGenerator;
return other != null &&
string.Equals(BaseType, other.BaseType, StringComparison.Ordinal);
}
public override int GetHashCode()
{
return BaseType.GetHashCode();
}
}
}

View File

@ -1,23 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{
internal class TypeMemberChunkGenerator : SpanChunkGenerator
{
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
{
//context.ChunkTreeBuilder.AddTypeMemberChunk(target.Content, target);
}
public override void Accept(ParserVisitor visitor, Span span)
{
visitor.VisitTypeMemberSpan(this, span);
}
public override string ToString()
{
return "TypeMember";
}
}
}

View File

@ -182,6 +182,9 @@
<data name="DirectiveExpectsIdentifier" xml:space="preserve">
<value>The '{0}' directive expects an identifier.</value>
</data>
<data name="DirectiveExpectsTypeName" xml:space="preserve">
<value>The '{0}' directive expects a type name.</value>
</data>
<data name="EndBlock_Called_Without_Matching_StartBlock" xml:space="preserve">
<value>"EndBlock" was called without a matching call to "StartBlock".</value>
</data>

View File

@ -346,6 +346,22 @@ namespace Microsoft.AspNetCore.Razor.Evolution
return string.Format(CultureInfo.CurrentCulture, GetString("DirectiveExpectsIdentifier"), p0);
}
/// <summary>
/// The '{0}' directive expects a type name.
/// </summary>
internal static string DirectiveExpectsTypeName
{
get { return GetString("DirectiveExpectsTypeName"); }
}
/// <summary>
/// The '{0}' directive expects a type name.
/// </summary>
internal static string FormatDirectiveExpectsTypeName(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("DirectiveExpectsTypeName"), p0);
}
/// <summary>
/// "EndBlock" was called without a matching call to "StartBlock".
/// </summary>

View File

@ -35,8 +35,13 @@ namespace Microsoft.AspNetCore.Razor.Evolution
builder.Phases.Add(new DefaultRazorIRLoweringPhase());
builder.Phases.Add(new DefaultRazorIRPhase());
// Syntax Tree passes
builder.Features.Add(new DefaultDirectiveSyntaxTreePass());
builder.Features.Add(new TagHelperBinderSyntaxTreePass());
builder.Features.Add(new HtmlNodeOptimizationPass());
// IR Passes
builder.Features.Add(new DefaultDirectiveIRPass());
}
public abstract IReadOnlyList<IRazorEngineFeature> Features { get; }

View File

@ -0,0 +1,95 @@
// 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.Evolution.Intermediate;
using Xunit;
using static Microsoft.AspNetCore.Razor.Evolution.Intermediate.RazorIRAssert;
namespace Microsoft.AspNetCore.Razor.Evolution
{
public class DefaultDirectiveIRPassTest
{
[Fact]
public void Execute_MutatesIRDocument()
{
// Arrange
var content =
@"@inherits Hello<World[]>
@functions {
var value = true;
}";
var originalIRDocument = Lower(content);
var pass = new DefaultDirectiveIRPass();
// Act
var irDocument = pass.Execute(codeDocument: null, irDocument: originalIRDocument);
// Assert
Assert.Same(originalIRDocument, irDocument);
}
[Fact]
public void Execute_Inherits_SetsClassDeclarationBaseType()
{
// Arrange
var content = "@inherits Hello<World[]>";
var originalIRDocument = Lower(content);
var pass = new DefaultDirectiveIRPass();
// Act
var irDocument = pass.Execute(codeDocument: null, irDocument: originalIRDocument);
// Assert
var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument);
var @class = SingleChild<ClassDeclarationIRNode>(@namespace);
Assert.Equal(@class.BaseType, "Hello<World[]>");
}
[Fact]
public void Execute_Functions_ExistsAtClassDeclarationAndMethodLevel()
{
// Arrange
var content = "@functions { var value = true; }";
var originalIRDocument = Lower(content);
var pass = new DefaultDirectiveIRPass();
// Act
var irDocument = pass.Execute(codeDocument: null, irDocument: originalIRDocument);
// Assert
var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument);
var @class = SingleChild<ClassDeclarationIRNode>(@namespace);
Children(@class,
node => Assert.IsType<RazorMethodDeclarationIRNode>(node),
node => CSharpStatement(" var value = true; ", node));
var method = (RazorMethodDeclarationIRNode)@class.Children[0];
Children(method,
node => Html(string.Empty, node),
node => Directive("functions", node,
directiveChild => CSharpStatement(" var value = true; ", directiveChild)),
node => Html(string.Empty, node));
}
private static DocumentIRNode Lower(string content)
{
var sourceDocument = TestRazorSourceDocument.Create(content);
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var engine = RazorEngine.Create();
for (var i = 0; i < engine.Phases.Count; i++)
{
var phase = engine.Phases[i];
phase.Execute(codeDocument);
if (phase is IRazorIRLoweringPhase)
{
break;
}
}
var irDocument = codeDocument.GetIRDocument();
Assert.NotNull(irDocument);
return irDocument;
}
}
}

View File

@ -0,0 +1,119 @@
// 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.Evolution.Legacy;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Evolution
{
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(22, 2, 4),
length: 8),
new RazorError(
LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS),
new SourceLocation(49, 4, 4),
length: 8),
};
var engine = RazorEngine.Create();
var pass = new DefaultDirectiveSyntaxTreePass()
{
Engine = engine,
};
var content =
@"
@section Foo {
@section Bar {
}
@section Baz {
}
}";
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.NotSame(originalTree, outputTree);
Assert.Equal(expectedErrors, 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(22, 2, 4),
length: 8),
new RazorError(
LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS),
new SourceLocation(49, 4, 4),
length: 8),
};
var engine = RazorEngine.Create();
var pass = new DefaultDirectiveSyntaxTreePass()
{
Engine = engine,
};
var content =
@"
@section Foo {
@section Bar {
}
@section Baz {
}
}";
var sourceDocument = TestRazorSourceDocument.Create(content);
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
var erroredOriginalTree = RazorSyntaxTree.Create(originalTree.Root, new[] { expectedErrors[0] }, originalTree.Options);
// Act
var outputTree = pass.Execute(codeDocument, erroredOriginalTree);
// Assert
Assert.Empty(originalTree.Diagnostics);
Assert.NotSame(originalTree, outputTree);
Assert.Equal(expectedErrors, outputTree.Diagnostics);
}
}
}

View File

@ -157,7 +157,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
var phase = engine.Phases[i];
phase.Execute(codeDocument);
if (phase is IRazorIRLoweringPhase)
if (phase is IRazorIRPhase)
{
break;
}

View File

@ -73,6 +73,34 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
}
}
public static void CSharpStatement(string expected, RazorIRNode node)
{
try
{
var statement = Assert.IsType<CSharpStatementIRNode>(node);
Assert.Equal(expected, statement.Content);
}
catch (XunitException e)
{
throw new IRAssertException(node, node.Children, e.Message, e);
}
}
public static void Directive(string expectedName, RazorIRNode node, params Action<RazorIRNode>[] childValidators)
{
try
{
var directive = Assert.IsType<DirectiveIRNode>(node);
Assert.Equal(expectedName, directive.Name);
}
catch (XunitException e)
{
throw new IRAssertException(node, node.Children, e.Message, e);
}
Children(node, childValidators);
}
public static void Using(string expected, RazorIRNode node)
{
try

View File

@ -47,26 +47,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
}
}
internal class FunctionsBlock : Block
{
private const BlockType ThisBlockType = BlockType.Functions;
public FunctionsBlock(IParentChunkGenerator chunkGenerator, IReadOnlyList<SyntaxTreeNode> children)
: base(ThisBlockType, children, chunkGenerator)
{
}
public FunctionsBlock(IParentChunkGenerator chunkGenerator, params SyntaxTreeNode[] children)
: this(chunkGenerator, (IReadOnlyList<SyntaxTreeNode>)children)
{
}
public FunctionsBlock(params SyntaxTreeNode[] children)
: this(ParentChunkGenerator.Null, children)
{
}
}
internal class ExpressionBlock : Block
{
private const BlockType ThisBlockType = BlockType.Expression;
@ -188,31 +168,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
}
}
internal class SectionBlock : Block
{
private const BlockType ThisBlockType = BlockType.Section;
public SectionBlock(IParentChunkGenerator chunkGenerator, IReadOnlyList<SyntaxTreeNode> children)
: base(ThisBlockType, children, chunkGenerator)
{
}
public SectionBlock(IParentChunkGenerator chunkGenerator, params SyntaxTreeNode[] children)
: this(chunkGenerator, (IReadOnlyList<SyntaxTreeNode>)children)
{
}
public SectionBlock(params SyntaxTreeNode[] children)
: this(ParentChunkGenerator.Null, children)
{
}
public SectionBlock(IReadOnlyList<SyntaxTreeNode> children)
: this(ParentChunkGenerator.Null, children)
{
}
}
internal class TemplateBlock : Block
{
private const BlockType ThisBlockType = BlockType.Template;

View File

@ -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 System.Linq;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
@ -13,19 +14,12 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{
ParseBlockTest(
"@functions{",
new FunctionsBlock(
Factory.CodeTransition("@")
.Accepts(AcceptedCharacters.None),
Factory.MetaCode("functions{")
.Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp()
.AsFunctionsBody()
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString)
{
AutoCompleteString = "}"
})),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("functions").Accepts(AcceptedCharacters.None),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharacters.None)),
new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("functions", "}", "{"),
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(CSharpCodeParser.FunctionsDirectiveDescriptor.Name, "}", "{"),
new SourceLocation(10, 0, 10),
length: 1));
}
@ -34,12 +28,17 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
public void SectionDirectiveAutoCompleteAtEOF()
{
ParseBlockTest("@section Header {",
new SectionBlock(new SectionChunkGenerator("Header"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section Header {")
.AutoCompleteWith("}", atEndOfSpan: true)
.Accepts(AcceptedCharacters.Any),
new MarkupBlock()),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "Header", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.EmptyHtml())),
new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("section", "}", "{"),
new SourceLocation(16, 0, 16),
@ -67,23 +66,16 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
[Fact]
public void FunctionsDirectiveAutoCompleteAtStartOfFile()
{
ParseBlockTest("@functions{" + Environment.NewLine
+ "foo",
new FunctionsBlock(
Factory.CodeTransition("@")
.Accepts(AcceptedCharacters.None),
Factory.MetaCode("functions{")
.Accepts(AcceptedCharacters.None),
Factory.Code(Environment.NewLine + "foo")
.AsFunctionsBody()
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString)
{
AutoCompleteString = "}"
})),
new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("functions", "}", "{"),
new SourceLocation(10, 0, 10),
length: 1));
ParseBlockTest("@functions{" + Environment.NewLine + "foo",
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("functions").Accepts(AcceptedCharacters.None),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharacters.None),
Factory.Code(Environment.NewLine + "foo").AsStatement()),
new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("functions", "}", "{"),
new SourceLocation(10, 0, 10),
length: 1));
}
[Fact]
@ -91,11 +83,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{
ParseBlockTest("@section Header {" + Environment.NewLine
+ "<p>Foo</p>",
new SectionBlock(new SectionChunkGenerator("Header"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section Header {")
.AutoCompleteWith("}", atEndOfSpan: true)
.Accepts(AcceptedCharacters.Any),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "Header", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(Environment.NewLine),
new MarkupTagBlock(

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
@ -148,7 +149,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
Factory.Span(SpanKind.Markup, "Header", markup: false)
.With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0]))
.Accepts(AcceptedCharacters.NonWhiteSpace),
Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{")
.AutoCompleteWith(null, atEndOfSpan: true)
.Accepts(AcceptedCharacters.None),
@ -181,7 +182,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
Factory.Span(SpanKind.Markup, "Name", markup: false)
.With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0]))
.Accepts(AcceptedCharacters.NonWhiteSpace),
Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{")
.AutoCompleteWith(null, atEndOfSpan: true)
.Accepts(AcceptedCharacters.None),
@ -218,7 +219,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
.Accepts(AcceptedCharacters.NonWhiteSpace),
Factory.Span(SpanKind.Markup, " ", markup: false)
.Accepts(AcceptedCharacters.AllWhiteSpace)));
.Accepts(AcceptedCharacters.WhiteSpace)));
}
[Fact]
@ -288,7 +289,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
.With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0]))
.Accepts(AcceptedCharacters.NonWhiteSpace),
Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.AllWhiteSpace)),
Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace)),
expectedErorr);
}
@ -315,7 +316,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
.With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0]))
.Accepts(AcceptedCharacters.NonWhiteSpace),
Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace)),
Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.AllWhiteSpace)),
expectedErorr);
}
@ -350,7 +351,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
// Arrange
var descriptor = DirectiveDescriptorBuilder.CreateCodeBlock("custom").AddString().Build();
var expectedErorr = new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("custom", "{", "}"),
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("custom", "}", "{"),
new SourceLocation(14, 0, 14),
length: 1);
@ -366,7 +367,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
Factory.Span(SpanKind.Markup, "Hello", markup: false)
.With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0]))
.Accepts(AcceptedCharacters.NonWhiteSpace),
Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{")
.AutoCompleteWith("}", atEndOfSpan: true)
.Accepts(AcceptedCharacters.None)),
@ -682,101 +683,93 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
public void InheritsDirective()
{
ParseBlockTest("@inherits System.Web.WebPages.WebPage",
new DirectiveBlock(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.InheritsKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("System.Web.WebPages.WebPage")
.AsBaseType("System.Web.WebPages.WebPage")));
Factory.MetaCode("inherits").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "System.Web.WebPages.WebPage", markup: false)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))));
}
[Fact]
public void InheritsDirectiveSupportsArrays()
{
ParseBlockTest("@inherits string[[]][]",
new DirectiveBlock(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.InheritsKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("string[[]][]")
.AsBaseType("string[[]][]")));
Factory.MetaCode("inherits").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "string[[]][]", markup: false)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))));
}
[Fact]
public void InheritsDirectiveSupportsNestedGenerics()
{
ParseBlockTest("@inherits System.Web.Mvc.WebViewPage<IEnumerable<MvcApplication2.Models.RegisterModel>>",
new DirectiveBlock(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.InheritsKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("System.Web.Mvc.WebViewPage<IEnumerable<MvcApplication2.Models.RegisterModel>>")
.AsBaseType("System.Web.Mvc.WebViewPage<IEnumerable<MvcApplication2.Models.RegisterModel>>")));
Factory.MetaCode("inherits").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "System.Web.Mvc.WebViewPage<IEnumerable<MvcApplication2.Models.RegisterModel>>", markup: false)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))));
}
[Fact]
public void InheritsDirectiveSupportsTypeKeywords()
{
ParseBlockTest("@inherits string",
new DirectiveBlock(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.InheritsKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("string")
.AsBaseType("string")));
}
[Fact]
public void InheritsDirectiveSupportsVSTemplateTokens()
{
ParseBlockTest("@inherits $rootnamespace$.MyBase",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.InheritsKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("$rootnamespace$.MyBase")
.AsBaseType("$rootnamespace$.MyBase")));
Factory.MetaCode("inherits").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "string", markup: false)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))));
}
[Fact]
public void FunctionsDirective()
{
ParseBlockTest("@functions { foo(); bar(); }",
new FunctionsBlock(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.FunctionsKeyword + " {")
.Accepts(AcceptedCharacters.None),
Factory.Code(" foo(); bar(); ")
.AsFunctionsBody()
.AutoCompleteWith(autoCompleteString: null),
Factory.MetaCode("}")
.Accepts(AcceptedCharacters.None)));
Factory.MetaCode("functions").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
Factory.Code(" foo(); bar(); ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void EmptyFunctionsDirective()
{
ParseBlockTest("@functions { }",
new FunctionsBlock(
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.FunctionsKeyword + " {")
.Accepts(AcceptedCharacters.None),
Factory.Code(" ")
.AsFunctionsBody()
.AutoCompleteWith(autoCompleteString: null),
Factory.MetaCode("}")
.Accepts(AcceptedCharacters.None)));
Factory.MetaCode("functions").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
Factory.Code(" ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void SectionDirective()
{
ParseBlockTest("@section Header { <p>F{o}o</p> }",
new SectionBlock(new SectionChunkGenerator("Header"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section Header {")
.AutoCompleteWith(null, atEndOfSpan: true)
.Accepts(AcceptedCharacters.Any),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "Header", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(" "),
new MarkupTagBlock(

View File

@ -299,15 +299,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
public void ParseBlockReportsErrorIfClassBlockUnterminatedAtEOF()
{
ParseBlockTest("functions { var foo = bar; if(foo != null) { bar(); } ",
new FunctionsBlock(
Factory.MetaCode("functions {").Accepts(AcceptedCharacters.None),
Factory.Code(" var foo = bar; if(foo != null) { bar(); } ")
.AsFunctionsBody()
.AutoCompleteWith("}")),
new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("functions", '}', '{'),
new SourceLocation(10, 0, 10),
length: 1));
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor),
Factory.MetaCode("functions").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharacters.None),
Factory.Code(" var foo = bar; if(foo != null) { bar(); } ").AsStatement()),
new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("functions", '}', '{'),
new SourceLocation(10, 0, 10),
length: 1));
}
[Fact]

View File

@ -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 System.Linq;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
@ -14,49 +15,52 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest("@section" + Environment.NewLine,
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator(string.Empty),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section" + Environment.NewLine))),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None)),
Factory.Markup(Environment.NewLine)),
new RazorError(
LegacyResources.FormatParseError_Unexpected_Character_At_Section_Name_Start(
LegacyResources.ErrorComponent_EndOfFile),
new SourceLocation(8 + Environment.NewLine.Length, 1, 0),
length: 1));
LegacyResources.FormatDirectiveExpectsIdentifier(CSharpCodeParser.SectionDirectiveDescriptor.Name),
new SourceLocation(8, 0, 8),
length: Environment.NewLine.Length));
}
[Fact]
public void ParseSectionBlockCapturesWhitespaceToEndOfLineInSectionStatementMissingOpenBrace()
{
ParseDocumentTest("@section Foo " + Environment.NewLine
+ " ",
ParseDocumentTest("@section Foo " + Environment.NewLine + " ",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("Foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section Foo " + Environment.NewLine)),
Factory.Markup(" ")),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " " + Environment.NewLine + " ", markup: false).Accepts(AcceptedCharacters.AllWhiteSpace)),
Factory.EmptyHtml()),
new RazorError(
LegacyResources.ParseError_MissingOpenBraceAfterSection,
new SourceLocation(12, 0, 12),
LegacyResources.FormatUnexpectedEOFAfterDirective(CSharpCodeParser.SectionDirectiveDescriptor.Name, "{"),
new SourceLocation(25 + Environment.NewLine.Length, 0, 25 + Environment.NewLine.Length),
length: 1));
}
[Fact]
public void ParseSectionBlockCapturesWhitespaceToEndOfLineInSectionStatementMissingName()
{
ParseDocumentTest("@section " + Environment.NewLine
+ " ",
ParseDocumentTest("@section " + Environment.NewLine + " ",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator(string.Empty),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section " + Environment.NewLine)),
Factory.Markup(" ")),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace)),
Factory.Markup(Environment.NewLine + " ")),
new RazorError(
LegacyResources.FormatParseError_Unexpected_Character_At_Section_Name_Start(
LegacyResources.ErrorComponent_EndOfFile),
new SourceLocation(21 + Environment.NewLine.Length, 1, 4),
length: 1));
LegacyResources.FormatDirectiveExpectsIdentifier(CSharpCodeParser.SectionDirectiveDescriptor.Name),
new SourceLocation(17, 0, 17),
length: Environment.NewLine.Length));
}
[Fact]
@ -79,19 +83,19 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest("@section 9 { <p>Foo</p> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator(string.Empty),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section ")),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace)),
Factory.Markup("9 { "),
new MarkupTagBlock(
Factory.Markup("<p>")),
Factory.Markup("Foo"),
new MarkupTagBlock(
Factory.Markup("</p>")),
Factory.Markup(" }")),
Factory.Markup(" }")),
new RazorError(
LegacyResources.FormatParseError_Unexpected_Character_At_Section_Name_Start(
LegacyResources.FormatErrorComponent_Character("9")),
LegacyResources.FormatDirectiveExpectsIdentifier(CSharpCodeParser.SectionDirectiveDescriptor.Name),
new SourceLocation(9, 0, 9),
length: 1));
}
@ -102,9 +106,13 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest("@section foo-bar { <p>Foo</p> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section foo")),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First()))),
Factory.Markup("-bar { "),
new MarkupTagBlock(
Factory.Markup("<p>")),
@ -113,7 +121,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
Factory.Markup("</p>")),
Factory.Markup(" }")),
new RazorError(
LegacyResources.ParseError_MissingOpenBraceAfterSection,
LegacyResources.FormatUnexpectedDirectiveLiteral(CSharpCodeParser.SectionDirectiveDescriptor.Name, "{"),
new SourceLocation(12, 0, 12),
length: 1));
}
@ -124,16 +132,26 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest("@section foo { @section bar { <p>Foo</p> } }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section foo {")
.AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(" "),
new SectionBlock(new SectionChunkGenerator("bar"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section bar {")
.AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "bar", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(" "),
new MarkupTagBlock(
@ -148,8 +166,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
Factory.EmptyHtml()),
new RazorError(
LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS),
new SourceLocation(16, 0, 16),
7));
new SourceLocation(15, 0, 15),
8));
}
[Fact]
@ -158,13 +176,19 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest("@section foo {",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section foo {")
.AutoCompleteWith("}", atEndOfSpan: true),
new MarkupBlock())),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.EmptyHtml()))),
new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("section", "}", "{"),
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(CSharpCodeParser.SectionDirectiveDescriptor.Name, "}", "{"),
new SourceLocation(13, 0, 13),
length: 1));
}
@ -179,10 +203,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest("@section foo {" + postStartBrace,
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section foo {")
.AutoCompleteWith("}", atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(postStartBrace)))),
new RazorError(
@ -197,10 +226,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest("@section foo { <p>Foo{}</p>",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section foo {")
.AutoCompleteWith("}", atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(" "),
new MarkupTagBlock(
@ -227,10 +261,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
spaces),
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("Test"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode($"section Test{newLine}{{")
.AutoCompleteWith("}", atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "Test", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, Environment.NewLine, CSharpSymbolType.NewLine).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(newLine),
new StatementBlock(
@ -256,12 +295,18 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest("@section foo " + Environment.NewLine,
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section foo " + Environment.NewLine))),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " " + Environment.NewLine, markup: false).Accepts(AcceptedCharacters.AllWhiteSpace)),
Factory.EmptyHtml()),
new RazorError(
LegacyResources.ParseError_MissingOpenBraceAfterSection,
new SourceLocation(12, 0, 12),
LegacyResources.FormatUnexpectedEOFAfterDirective(CSharpCodeParser.SectionDirectiveDescriptor.Name, "{"),
new SourceLocation(18 + Environment.NewLine.Length, 0, 18 + Environment.NewLine.Length),
length: 1));
}
@ -279,10 +324,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
+ "}",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode(string.Format("section foo {0}{0}{0}{0}{0}{0}{{", Environment.NewLine))
.AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " " + string.Format("{0}{0}{0}{0}{0}{0}", Environment.NewLine), markup: false).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(Environment.NewLine),
new MarkupTagBlock(
@ -301,10 +351,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest("@section foo { <p>Foo</p> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section foo {")
.AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(" "),
new MarkupTagBlock(
@ -323,10 +378,14 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest("@section foo{ <p>Foo</p> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section foo{")
.AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(" "),
new MarkupTagBlock(
@ -345,10 +404,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest("@section foo { <script>(function foo() { return 1; })();</script> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section foo {")
.AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(" "),
new MarkupTagBlock(
@ -367,10 +431,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest("@section foo { I really want to render a close brace, so here I go: @(\"}\") }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section foo {")
.AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(" I really want to render a close brace, so here I go: "),
new ExpressionBlock(
@ -392,10 +461,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
+ "}",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("Foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section Foo {")
.AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(Environment.NewLine),
new StatementBlock(
@ -414,10 +488,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
+ "}}",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("Foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section Foo {")
.AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(Environment.NewLine),
new StatementBlock(
@ -434,10 +513,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest("@section foo {something}",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section foo {")
.AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup("something")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
@ -450,10 +534,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest("@section s {<!-- -->}",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("s"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section s {")
.AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup("<!-- -->")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
@ -468,10 +557,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest("@section s {<!-- > \" '-->}",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("s"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section s {")
.AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup("<!-- > \" '-->")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
@ -485,10 +579,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
"@section s {" + Environment.NewLine + "<a" + Environment.NewLine + "<!-- > \" '-->}",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("s"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section s {")
.AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(Environment.NewLine),
new MarkupTagBlock(
@ -505,10 +604,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
"@section s { <? xml bleh ?>}",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("s"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section s {")
.AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(" <? xml bleh ?>")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
@ -527,10 +631,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
"@section s {<span foo='@@' />}",
new MarkupBlock(
factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("s"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
factory.CodeTransition(),
factory.MetaCode("section s {")
.AutoCompleteWith(null, atEndOfSpan: true),
factory.MetaCode("section").Accepts(AcceptedCharacters.None),
factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
new MarkupTagBlock(
factory.Markup("<span"),
@ -549,10 +658,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
"@section s {<span foo='@DateTime.Now @@' />}",
new MarkupBlock(
factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("s"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
factory.CodeTransition(),
factory.MetaCode("section s {")
.AutoCompleteWith(null, atEndOfSpan: true),
factory.MetaCode("section").Accepts(AcceptedCharacters.None),
factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
new MarkupTagBlock(
factory.Markup("<span"),

View File

@ -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 System.Linq;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
@ -12,36 +13,33 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
public void ParseInheritsStatementMarksInheritsSpanAsCanGrowIfMissingTrailingSpace()
{
ParseBlockTest("inherits",
new DirectiveBlock(
Factory.MetaCode("inherits").Accepts(AcceptedCharacters.Any)
),
new RazorError(
LegacyResources.ParseError_InheritsKeyword_Must_Be_Followed_By_TypeName,
new SourceLocation(0, 0, 0), 8));
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor),
Factory.MetaCode("inherits").Accepts(AcceptedCharacters.None)),
new RazorError(
LegacyResources.FormatUnexpectedEOFAfterDirective(CSharpCodeParser.InheritsDirectiveDescriptor.Name, "type"),
new SourceLocation(8, 0, 8), 1));
}
[Fact]
public void InheritsBlockAcceptsMultipleGenericArguments()
{
ParseBlockTest("inherits Foo.Bar<Biz<Qux>, string, int>.Baz",
new DirectiveBlock(
Factory.MetaCode("inherits ").Accepts(AcceptedCharacters.None),
Factory.Code("Foo.Bar<Biz<Qux>, string, int>.Baz")
.AsBaseType("Foo.Bar<Biz<Qux>, string, int>.Baz")
));
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor),
Factory.MetaCode("inherits").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "Foo.Bar<Biz<Qux>, string, int>.Baz", markup: false)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))));
}
[Fact]
public void InheritsBlockOutputsErrorIfInheritsNotFollowedByTypeButAcceptsEntireLineAsCode()
{
ParseBlockTest("inherits " + Environment.NewLine
+ "foo",
new DirectiveBlock(
Factory.MetaCode("inherits ").Accepts(AcceptedCharacters.None),
Factory.Code(" " + Environment.NewLine)
.AsBaseType(string.Empty)
),
new RazorError(LegacyResources.ParseError_InheritsKeyword_Must_Be_Followed_By_TypeName, 0, 0, 0, 8));
ParseBlockTest("inherits " + Environment.NewLine + "foo",
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor),
Factory.MetaCode("inherits").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace)),
new RazorError(LegacyResources.FormatDirectiveExpectsTypeName(CSharpCodeParser.InheritsDirectiveDescriptor.Name), 24, 0, 24, 2));
}
[Fact]
@ -143,29 +141,27 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{
const string code = " foo(); \"bar}baz\" ";
ParseBlockTest("functions {" + code + "} zoop",
new FunctionsBlock(
Factory.MetaCode("functions {").Accepts(AcceptedCharacters.None),
Factory.Code(code)
.AsFunctionsBody()
.AutoCompleteWith(autoCompleteString: null),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
));
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor),
Factory.MetaCode("functions").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
Factory.Code(code).AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockDoesNoErrorRecoveryForFunctionsBlock()
{
ParseBlockTest("functions { { { { { } zoop",
new FunctionsBlock(
Factory.MetaCode("functions {").Accepts(AcceptedCharacters.None),
Factory.Code(" { { { { } zoop")
.AsFunctionsBody()
.AutoCompleteWith("}")
),
new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("functions", "}", "{"),
new SourceLocation(10, 0, 10),
length: 1));
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor),
Factory.MetaCode("functions").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharacters.None),
Factory.Code(" { { { { } zoop").AsStatement()),
new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("functions", "}", "{"),
new SourceLocation(10, 0, 10),
length: 1));
}
[Fact]

View File

@ -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 System.Linq;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
@ -108,10 +109,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
+ "}",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("Foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section Foo {")
.AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(Environment.NewLine + " "),
BlockFactory.MarkupTagBlock("<html>"),
@ -468,10 +474,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest(@"@section Foo { <script>foo<bar baz='@boz'></script> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("Foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section Foo {")
.AutoCompleteWith(autoCompleteString: null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(" "),
BlockFactory.MarkupTagBlock("<script>"),

View File

@ -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 System.Linq;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
@ -280,6 +281,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
[Fact]
public void SectionContextGivesWhitespacePreceedingAtToCodeIfThereIsNoMarkupOnThatLine()
{
var sectionDescriptor = CSharpCodeParser.SectionDirectiveDescriptor;
ParseDocumentTest("@section foo {" + Environment.NewLine
+ " <ul>" + Environment.NewLine
+ " @foreach(var p in Products) {" + Environment.NewLine
@ -289,9 +291,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
+ "}",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section foo {").AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(Environment.NewLine + " "),
new MarkupTagBlock(
@ -386,9 +394,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest("@section Foo { <foo>@@bar</foo> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("Foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section Foo {").AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(" "),
new MarkupTagBlock(
@ -408,9 +422,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
ParseDocumentTest("@section Foo { <foo>@@@@@bar</foo> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionChunkGenerator("Foo"),
new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor),
Factory.CodeTransition(),
Factory.MetaCode("section Foo {").AutoCompleteWith(null, atEndOfSpan: true),
Factory.MetaCode("section").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace),
Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier)
.Accepts(AcceptedCharacters.NonWhiteSpace)
.With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())),
Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None),
new MarkupBlock(
Factory.Markup(" "),
new MarkupTagBlock(

View File

@ -34,7 +34,11 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
var parser = new RazorParser(options);
return parser.Parse((ITextDocument)reader);
var tree = parser.Parse((ITextDocument)reader);
var defaultDirectivePass = new DefaultDirectiveSyntaxTreePass();
tree = defaultDirectivePass.Execute(codeDocument: null, syntaxTree: tree);
return tree;
}
}

View File

@ -313,11 +313,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
.With(new ExpressionChunkGenerator());
}
public SpanConstructor AsFunctionsBody()
{
return _self.With(new TypeMemberChunkGenerator());
}
public SpanConstructor AsNamespaceImport(string ns)
{
return _self.With(new AddImportChunkGenerator(ns));
@ -328,13 +323,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
return _self.With(SpanChunkGenerator.Null);
}
public SpanConstructor AsBaseType(string baseType)
{
return _self
.With(new SetBaseTypeChunkGenerator(baseType))
.Accepts(AcceptedCharacters.AnyExceptNewline);
}
public SpanConstructor AsAddTagHelper(string lookupText)
{
return _self

View File

@ -75,8 +75,10 @@ namespace Microsoft.AspNetCore.Razor.Evolution
{
Assert.Collection(
features,
feature => Assert.IsType<DefaultDirectiveSyntaxTreePass>(feature),
feature => Assert.IsType<TagHelperBinderSyntaxTreePass>(feature),
feature => Assert.IsType<HtmlNodeOptimizationPass>(feature));
feature => Assert.IsType<HtmlNodeOptimizationPass>(feature),
feature => Assert.IsType<DefaultDirectiveIRPass>(feature));
}
private static void AssertDefaultPhases(IReadOnlyList<IRazorEnginePhase> phases)