From f25c278626f81b0d866238bb8915c0ce74cf67f5 Mon Sep 17 00:00:00 2001 From: Kira-NT Date: Sun, 19 Jul 2026 16:16:42 +0100 Subject: [PATCH 1/3] Add basic support for JSON-style comments --- YamlDotNet.Test/Core/ScannerTests.cs | 83 ++++++++++++++++++++ YamlDotNet/Core/Scanner.cs | 109 ++++++++++++++++++++++----- 2 files changed, 172 insertions(+), 20 deletions(-) diff --git a/YamlDotNet.Test/Core/ScannerTests.cs b/YamlDotNet.Test/Core/ScannerTests.cs index 408a524b..d723cb46 100644 --- a/YamlDotNet.Test/Core/ScannerTests.cs +++ b/YamlDotNet.Test/Core/ScannerTests.cs @@ -389,6 +389,89 @@ public void CommentsAreOmittedUnlessRequested() StreamEnd); } + [Fact] + public void JsonCommentsAreReturnedWhenRequested() + { + AssertSequenceOfTokensFrom(new Scanner(Yaml.ReaderForText(@" + // Top comment + - first // Comment on first item + - second /* First comment on second item */ /* Second comment on second item */ + /* + * Bottom comment + */ + "), skipComments: false, allowJsonComments: true, maxKeySize: 1024), + StreamStart, + StandaloneComment("Top comment"), + BlockSequenceStart, + BlockEntry, + PlainScalar("first"), + InlineComment("Comment on first item"), + BlockEntry, + PlainScalar("second"), + InlineComment("First comment on second item "), + InlineComment("Second comment on second item "), + StandaloneComment("\n * Bottom comment\n "), + BlockEnd, + StreamEnd); + } + + [Fact] + public void JsonCommentsAreCorrectlyMarked() + { + var sut = new Scanner(Yaml.ReaderForText(@" + /* + * Comment before first item + */ + - first // Comment on first item + "), skipComments: false, allowJsonComments: true, maxKeySize: 1024); + + + while (sut.MoveNext()) + { + if (sut.Current is Comment comment) + { + Assert.Equal(0, comment.Start.Index); + Assert.Equal(35, comment.End.Index); + + break; + } + } + + while (sut.MoveNext()) + { + if (sut.Current is Comment comment) + { + Assert.Equal(44, comment.Start.Index); + Assert.Equal(68, comment.End.Index); + + return; + } + } + + Assert.Fail("Did not find the comments"); + } + + [Fact] + public void JsonCommentsAreOmittedUnlessRequested() + { + AssertSequenceOfTokensFrom(new Scanner(Yaml.ReaderForText(@" + // Top comment + - first // Comment on first item + - second /* First comment on second item */ /* Second comment on second item */ + /* + * Bottom comment + */ + "), skipComments: true, allowJsonComments: true, maxKeySize: 1024), + StreamStart, + BlockSequenceStart, + BlockEntry, + PlainScalar("first"), + BlockEntry, + PlainScalar("second"), + BlockEnd, + StreamEnd); + } + [Fact] public void MarksOnDoubleQuotedScalarsAreCorrect() { diff --git a/YamlDotNet/Core/Scanner.cs b/YamlDotNet/Core/Scanner.cs index 4cabd49a..cc95d792 100644 --- a/YamlDotNet/Core/Scanner.cs +++ b/YamlDotNet/Core/Scanner.cs @@ -102,6 +102,11 @@ public bool SkipComments get; private set; } + internal bool AllowJsonComments + { + get; private set; + } + /// /// Gets the current token. /// @@ -134,6 +139,12 @@ public Scanner(TextReader input, bool skipComments, int maxKeySize) this.maxKeySize = maxKeySize; } + internal Scanner(TextReader input, bool skipComments, bool allowJsonComments, int maxKeySize) + : this(input, skipComments, maxKeySize) + { + AllowJsonComments = allowJsonComments; + } + /// /// Gets the current position inside the input stream. /// @@ -508,7 +519,10 @@ private void FetchNextToken() // The last rule is more restrictive than the specification requires. - var isInvalidPlainScalarCharacter = analyzer.IsWhiteBreakOrZero() || analyzer.Check("-?:,[]{}#&*!|>'\"%@`"); + var isInvalidPlainScalarCharacter = + analyzer.IsWhiteBreakOrZero() || + analyzer.Check("-?:,[]{}#&*!|>'\"%@`") || + AllowJsonComments && CheckJsonComment(); var isPlainScalar = !isInvalidPlainScalarCharacter || @@ -565,6 +579,16 @@ private bool CheckWhiteSpace() return analyzer.Check(' ') || ((flowLevel > 0 || !simpleKeyAllowed) && analyzer.Check('\t')); } + private bool CheckComment() + { + return analyzer.Check('#') || AllowJsonComments && CheckJsonComment(); + } + + private bool CheckJsonComment() + { + return analyzer.Check('/') && analyzer.Check("/*", 1); + } + private void Skip() { cursor.Skip(); @@ -636,36 +660,81 @@ private void ScanToNextToken() private void ProcessComment() { - if (analyzer.Check('#')) + // Only JSON comments can be stacked next to each other on a single line, + // so unless they are enabled, there's no need to check for a comment more than once. + while (ProcessNextComment() && AllowJsonComments) { } + } + + private bool ProcessNextComment() + { + var isJsonComment = false; + var isMultilineComment = false; + var isComment = + analyzer.Check('#') || + AllowJsonComments && analyzer.Check('/') && + (isJsonComment = (isMultilineComment = analyzer.Check('*', 1)) || analyzer.Check('/', 1)); + + if (!isComment) { - var start = cursor.Mark(); + return false; + } + var start = cursor.Mark(); - // Eat '#' + // Eat "#", "//", or "/*" + Skip(); + if (isJsonComment) + { Skip(); + } - // Eat leading whitespace - while (analyzer.IsSpace()) + // Eat leading whitespace + while (analyzer.IsSpace()) + { + Skip(); + } + + using var textBuilder = StringBuilderPool.Rent(); + var text = textBuilder.Builder; + if (isMultilineComment) + { + // Eat everything until "*/" + while (!analyzer.IsZero()) { - Skip(); + if (analyzer.Check('*') && analyzer.Check('/', 1)) + { + Skip(); + Skip(); + break; + } + text.Append(ReadCurrentCharacter()); } - using var textBuilder = StringBuilderPool.Rent(); - var text = textBuilder.Builder; + // Eat any remaining whitespace in case another comment + // follows immediately after this one + while (CheckWhiteSpace()) + { + Skip(); + } + } + else + { + // Eat everything until the end of the line while (!analyzer.IsBreakOrZero()) { text.Append(ReadCurrentCharacter()); } + } - if (!SkipComments) - { - var isInline = previous != null - && previous.End.Line == start.Line - && previous.End.Column != 1 - && !(previous is StreamStart); + if (!SkipComments) + { + var isInline = previous != null + && previous.End.Line == start.Line + && previous.End.Column != 1 + && !(previous is StreamStart); - tokens.Enqueue(new Comment(text.ToString(), isInline, start, cursor.Mark())); - } + tokens.Enqueue(new Comment(text.ToString(), isInline, start, cursor.Mark())); } + return true; } private void FetchStreamStart() @@ -808,7 +877,7 @@ private void FetchDirective() default: // warning: skipping reserved directive line - while (!analyzer.EndOfInput && !analyzer.Check('#') && !analyzer.IsBreak()) + while (!analyzer.EndOfInput && !CheckComment() && !analyzer.IsBreak()) { Skip(); } @@ -872,7 +941,7 @@ private void FetchDocumentIndicator(bool isStartToken) else { Token? errorToken = null; - while (!analyzer.EndOfInput && !analyzer.IsBreak() && !analyzer.Check('#')) + while (!analyzer.EndOfInput && !analyzer.IsBreak() && !CheckComment()) { if (!analyzer.IsWhite()) { @@ -2148,7 +2217,7 @@ private Scalar ScanPlainScalar(ref bool isMultiline) // Check for a comment. - if (analyzer.Check('#')) + if (CheckComment()) { if (indent < 0 && flowLevel == 0) { From 0306eaf1402747baeff9ee6e06c9c41d5815121d Mon Sep 17 00:00:00 2001 From: Kira-NT Date: Mon, 20 Jul 2026 02:12:06 +0100 Subject: [PATCH 2/3] Allow JSON comments after literal values --- YamlDotNet.Test/Core/ScannerTests.cs | 68 ++++++++++++ YamlDotNet.Test/Helpers/JsonHelperTests.cs | 114 +++++++++++++++++++++ YamlDotNet/Core/Scanner.cs | 8 ++ YamlDotNet/Helpers/JsonHelper.cs | 96 +++++++++++++++++ 4 files changed, 286 insertions(+) create mode 100644 YamlDotNet.Test/Helpers/JsonHelperTests.cs create mode 100644 YamlDotNet/Helpers/JsonHelper.cs diff --git a/YamlDotNet.Test/Core/ScannerTests.cs b/YamlDotNet.Test/Core/ScannerTests.cs index d723cb46..6c608932 100644 --- a/YamlDotNet.Test/Core/ScannerTests.cs +++ b/YamlDotNet.Test/Core/ScannerTests.cs @@ -472,6 +472,74 @@ public void JsonCommentsAreOmittedUnlessRequested() StreamEnd); } + [Fact] + public void JsonCommentsAreAllowedAfterValues() + { + AssertSequenceOfTokensFrom(new Scanner(Yaml.ReaderForText(@" + { + comma: 1,// comment after comma + singleQuotes: '1'// comment after single-quoted string + doubleQuotes: ""1""// comment after double-quoted string + object: {}//comment after object + array: []//comment after array + null: null//comment after null + false: false//comment after false + true: true//comment after true + positiveNumber: 123.4e5//comment after positive number + negativeNumber: -123.4E-5//comment after negative number + } + "), skipComments: false, allowJsonComments: true, maxKeySize: 1024), + StreamStart, + FlowMappingStart, + Key, + PlainScalar("comma"), + Value, + PlainScalar("1"), + FlowEntry, + InlineComment("comment after comma"), + Key, + PlainScalar("singleQuotes"), + Value, + SingleQuotedScalar("1"), + InlineComment("comment after single-quoted string"), + PlainScalar("doubleQuotes"), + Value, + DoubleQuotedScalar("1"), + InlineComment("comment after double-quoted string"), + PlainScalar("object"), + Value, + FlowMappingStart, + FlowMappingEnd, + InlineComment("comment after object"), + PlainScalar("array"), + Value, + FlowSequenceStart, + FlowSequenceEnd, + InlineComment("comment after array"), + PlainScalar("null"), + Value, + PlainScalar("null"), + InlineComment("comment after null"), + PlainScalar("false"), + Value, + PlainScalar("false"), + InlineComment("comment after false"), + PlainScalar("true"), + Value, + PlainScalar("true"), + InlineComment("comment after true"), + PlainScalar("positiveNumber"), + Value, + PlainScalar("123.4e5"), + InlineComment("comment after positive number"), + PlainScalar("negativeNumber"), + Value, + PlainScalar("-123.4E-5"), + InlineComment("comment after negative number"), + FlowMappingEnd, + StreamEnd); + } + [Fact] public void MarksOnDoubleQuotedScalarsAreCorrect() { diff --git a/YamlDotNet.Test/Helpers/JsonHelperTests.cs b/YamlDotNet.Test/Helpers/JsonHelperTests.cs new file mode 100644 index 00000000..85f6b32b --- /dev/null +++ b/YamlDotNet.Test/Helpers/JsonHelperTests.cs @@ -0,0 +1,114 @@ +// This file is part of YamlDotNet - A .NET library for YAML. +// Copyright (c) Antoine Aubry and contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +using System.Text; +using Xunit; +using YamlDotNet.Helpers; + +namespace YamlDotNet.Test.Helpers +{ + public class JsonHelperTests + { + [Fact] + public void IsJsonLiteralReturnsTrueForNull() + { + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("null"))); + } + + [Fact] + public void IsJsonLiteralReturnsTrueForBooleans() + { + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("true"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("false"))); + } + + [Fact] + public void IsJsonLiteralReturnsTrueForNumbers() + { + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("0"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("-0"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("0.0"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("-0.0"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("0e0"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("0e+0"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("0e-0"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("-0e0"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("-0e+0"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("-0e-0"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("0.0e0"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("0.0e+0"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("0.0e-0"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("-0.0e0"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("-0.0e+0"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("-0.0e-0"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("123"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("-123"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("123.45"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("-123.45"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("123e45"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("123e+45"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("123e-45"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("-123e45"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("-123e+45"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("-123e-45"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("123.45e67"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("123.45e+67"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("123.45e-67"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("-123.45e67"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("-123.45e+67"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("-123.45e-67"))); + Assert.True(JsonHelper.IsJsonLiteral(new StringBuilder("-123.45E+67"))); + } + + [Fact] + public void IsJsonLiteralReturnsFalseForNonLiteralValues() + { + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("foo"))); + + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("Null"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("True"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("False"))); + + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("NULL"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("TRUE"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("FALSE"))); + + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("-"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("+"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("+123"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("01"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("-01"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("123.45.67"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("123."))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder(".123"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("."))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("123.45e67e8"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("123.45e67.8"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("123e67.8"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("123.45e"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("123.45e+"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("123.45e-"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("e"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("0xcoffee"))); + Assert.False(JsonHelper.IsJsonLiteral(new StringBuilder("0b101010"))); + } + } +} diff --git a/YamlDotNet/Core/Scanner.cs b/YamlDotNet/Core/Scanner.cs index cc95d792..e40473b2 100644 --- a/YamlDotNet/Core/Scanner.cs +++ b/YamlDotNet/Core/Scanner.cs @@ -26,6 +26,7 @@ using System.Text; using YamlDotNet.Core.ObjectPool; using YamlDotNet.Core.Tokens; +using YamlDotNet.Helpers; namespace YamlDotNet.Core { @@ -2246,6 +2247,13 @@ private Scalar ScanPlainScalar(ref bool isMultiline) break; } + // Check for a comment that may end a JSON-style literal. + + if (AllowJsonComments && flowLevel > 0 && CheckJsonComment() && JsonHelper.IsJsonLiteral(value)) + { + break; + } + // Check if we need to join whitespaces and breaks. if (hasLeadingBlanks || whitespaces.Length > 0) diff --git a/YamlDotNet/Helpers/JsonHelper.cs b/YamlDotNet/Helpers/JsonHelper.cs new file mode 100644 index 00000000..78963724 --- /dev/null +++ b/YamlDotNet/Helpers/JsonHelper.cs @@ -0,0 +1,96 @@ +// This file is part of YamlDotNet - A .NET library for YAML. +// Copyright (c) Antoine Aubry and contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +using System.Text; + +namespace YamlDotNet.Helpers +{ + internal static class JsonHelper + { + public static bool IsJsonLiteral(StringBuilder s) + { + var l = s.Length; + + // Check whether the value is the literal "null", "true", or "false". + switch (l) + { + case 0: + return false; + + case 4 when s[0] == 'n' && s[1] == 'u' && s[2] == 'l' && s[3] == 'l': + case 4 when s[0] == 't' && s[1] == 'r' && s[2] == 'u' && s[3] == 'e': + case 5 when s[0] == 'f' && s[1] == 'a' && s[2] == 'l' && s[3] == 's' && s[4] == 'e': + return true; + } + + // Check whether the value represents a valid number. + var i = 0; + var hasDot = false; + var hasExponent = false; + + // The first character after an optional minus sign must be a digit. + // Leading zeros are not allowed. + if (s[i] == '-' && ++i == l || (uint)(s[i] - '0') > 9 || s[i] == '0' && ++i < l && (uint)(s[i] - '0') <= 9) + { + return false; + } + + for (; i < l; i++) + { + var c = s[i]; + if (c == '.') + { + // The number may contain only a single decimal point, + // which must be followed by at least one digit. + if (hasDot || ++i == l || (uint)(s[i] - '0') > 9) + { + return false; + } + + hasDot = true; + } + else if ((c | 0x20) == 'e') + { + // Skip an optional plus or minus sign. + if (i + 1 < l && s[i + 1] is '+' or '-') + { + i++; + } + + // The number may contain only a single exponent, + // which must be be followed by at least one digit. + if (hasExponent || i + 1 >= l) + { + return false; + } + + hasDot = true; + hasExponent = true; + } + else if ((uint)(c - '0') > 9) + { + return false; + } + } + return true; + } + } +} From 07ca78b76cb16dbb5e89cc0994c5c3cefd4f1ba4 Mon Sep 17 00:00:00 2001 From: Kira-NT Date: Mon, 20 Jul 2026 02:42:59 +0100 Subject: [PATCH 3/3] Mark multiline JSON comments as standalone --- YamlDotNet.Test/Core/ScannerTests.cs | 49 +++++++++++++++++++++++++++- YamlDotNet/Core/Scanner.cs | 6 ++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/YamlDotNet.Test/Core/ScannerTests.cs b/YamlDotNet.Test/Core/ScannerTests.cs index 6c608932..3c41aa4f 100644 --- a/YamlDotNet.Test/Core/ScannerTests.cs +++ b/YamlDotNet.Test/Core/ScannerTests.cs @@ -408,7 +408,7 @@ public void JsonCommentsAreReturnedWhenRequested() InlineComment("Comment on first item"), BlockEntry, PlainScalar("second"), - InlineComment("First comment on second item "), + StandaloneComment("First comment on second item "), InlineComment("Second comment on second item "), StandaloneComment("\n * Bottom comment\n "), BlockEnd, @@ -540,6 +540,53 @@ public void JsonCommentsAreAllowedAfterValues() StreamEnd); } + [Fact] + public void MultilineJsonCommentsAreMarkedAsStandalone() + { + AssertSequenceOfTokensFrom(new Scanner(Yaml.ReaderForText(@" + { + /* + * Top comment. + */ + /*0*/ /*1*/""foo""/*2*/ /*3*/:/*4*/ /*5*/false/*6*/ /*7*/,// 8 + // Middle comment. + /*9*/""bar""/*10*/:/*11*/true/*12*/ + /* + * Bottom comment. + */ + } + "), skipComments: false, allowJsonComments: true, maxKeySize: 1024), + StreamStart, + FlowMappingStart, + StandaloneComment("\n * Top comment.\n "), + StandaloneComment("0"), + StandaloneComment("1"), + Key, + DoubleQuotedScalar("foo"), + StandaloneComment("2"), + StandaloneComment("3"), + Value, + StandaloneComment("4"), + StandaloneComment("5"), + PlainScalar("false"), + StandaloneComment("6"), + StandaloneComment("7"), + FlowEntry, + InlineComment("8"), + StandaloneComment("Middle comment."), + StandaloneComment("9"), + Key, + DoubleQuotedScalar("bar"), + StandaloneComment("10"), + Value, + StandaloneComment("11"), + PlainScalar("true"), + InlineComment("12"), + StandaloneComment("\n * Bottom comment.\n "), + FlowMappingEnd, + StreamEnd); + } + [Fact] public void MarksOnDoubleQuotedScalarsAreCorrect() { diff --git a/YamlDotNet/Core/Scanner.cs b/YamlDotNet/Core/Scanner.cs index e40473b2..ed2c0153 100644 --- a/YamlDotNet/Core/Scanner.cs +++ b/YamlDotNet/Core/Scanner.cs @@ -728,12 +728,14 @@ private bool ProcessNextComment() if (!SkipComments) { + var end = cursor.Mark(); var isInline = previous != null && previous.End.Line == start.Line && previous.End.Column != 1 - && !(previous is StreamStart); + && !(previous is StreamStart) + && (!isMultilineComment || start.Line == end.Line && analyzer.IsBreakOrZero()); - tokens.Enqueue(new Comment(text.ToString(), isInline, start, cursor.Mark())); + tokens.Enqueue(new Comment(text.ToString(), isInline, start, end)); } return true; }