diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/CSharpCodeParser.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/CSharpCodeParser.cs index fb4fa75fc4..39694cfdfc 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/CSharpCodeParser.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/CSharpCodeParser.cs @@ -1553,7 +1553,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy outputKind = SpanKind.Code; break; case DirectiveTokenKind.String: - AcceptAndMoveNext(); + AcceptUntil(CSharpSymbolType.WhiteSpace, CSharpSymbolType.NewLine); + NextToken(); break; } diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/CSharpDirectivesTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/CSharpDirectivesTest.cs index 639e5b88d7..17edc72ff0 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/CSharpDirectivesTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/CSharpDirectivesTest.cs @@ -751,6 +751,29 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace))); } + [Theory] + [InlineData("token")] + [InlineData("{formaction?}/{id}?")] + public void OptionalDirectiveTokens_AreParsed(string value) + { + // Arrange + var descriptor = DirectiveDescriptorBuilder.Create("custom").BeginOptionals().AddString().Build(); + var chunkGenerator = new DirectiveTokenChunkGenerator(descriptor.Tokens.First()); + + // Act & Assert + ParseCodeBlockTest( + $"@custom {value}", + new[] { descriptor }, + new DirectiveBlock( + new DirectiveChunkGenerator(descriptor), + Factory.CodeTransition(), + Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), + Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), + Factory.Span(SpanKind.Markup, value, markup: false) + .Accepts(AcceptedCharacters.NonWhiteSpace) + .With(chunkGenerator))); + } + internal virtual void ParseCodeBlockTest( string document, IEnumerable descriptors,