Skip to content

Commit bdf10c4

Browse files
committed
Better handling of the block chomping indicator
The Block chomping indicators affects how the final line break is interpreted. So use "strip" when the value doesn't ends with a line break, "clip" when the value ends with a line break, and "keep" when the value ends with multiple line breaks.
1 parent e38c0d4 commit bdf10c4

File tree

2 files changed

+64
-16
lines changed

2 files changed

+64
-16
lines changed

src/Microsoft.OpenApi/Writers/OpenApiYamlWriter.cs

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -182,12 +182,8 @@ public override void WriteValue(string value)
182182

183183
Writer.Write("|");
184184

185-
// Write chomping indicator when it ends with line break.
186-
if (value.LastIndexOfAny(new []{'\n', '\r'}) == value.Length - 1)
187-
{
188-
Writer.Write("+");
189-
}
190-
185+
WriteChompingIndicator(value);
186+
191187
// Write indentation indicator when it starts with spaces
192188
if (value.StartsWith(" "))
193189
{
@@ -222,6 +218,54 @@ public override void WriteValue(string value)
222218
}
223219
}
224220

221+
private void WriteChompingIndicator(string value)
222+
{
223+
var trailingNewlines = 0;
224+
var end = value.Length - 1;
225+
// We only need to know whether there are 0, 1, or more trailing newlines
226+
while (end >= 0 && trailingNewlines < 2)
227+
{
228+
var found = value.LastIndexOfAny(new[] { '\n', '\r' }, end, 2);
229+
if (found == -1 || found != end)
230+
{
231+
// does not ends with newline
232+
break;
233+
}
234+
235+
if (value[end] == '\r')
236+
{
237+
// ends with \r
238+
end--;
239+
}
240+
else if (end > 0 && value[end - 1] == '\r')
241+
{
242+
// ends with \r\n
243+
end -= 2;
244+
}
245+
else
246+
{
247+
// ends with \n
248+
end -= 1;
249+
}
250+
trailingNewlines++;
251+
}
252+
253+
switch (trailingNewlines)
254+
{
255+
case 0:
256+
// "strip" chomping indicator
257+
Writer.Write("-");
258+
break;
259+
case 1:
260+
// "clip"
261+
break;
262+
default:
263+
// "keep" chomping indicator
264+
Writer.Write("+");
265+
break;
266+
}
267+
}
268+
225269
/// <summary>
226270
/// Write null value.
227271
/// </summary>

test/Microsoft.OpenApi.Tests/Writers/OpenApiWriterSpecialCharacterTests.cs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,13 @@ public void WriteStringWithSpecialCharactersAsYamlWorks(string input, string exp
7777
}
7878

7979
[Theory]
80-
[InlineData("multiline\r\nstring", "test: |\n multiline\n string")]
81-
[InlineData("ends with\r\nline break\r\n", "test: |+\n ends with\n line break")]
82-
[InlineData(" starts with\nspaces", "test: |2\n starts with\n spaces")]
83-
[InlineData(" starts with\nspaces, and ends with line break\n", "test: |+2\n starts with\n spaces, and ends with line break")]
84-
[InlineData("contains\n\n\nempty lines", "test: |\n contains\n\n\n empty lines")]
80+
[InlineData("multiline\r\nstring", "test: |-\n multiline\n string")]
81+
[InlineData("ends with\r\nline break\r\n", "test: |\n ends with\n line break")]
82+
[InlineData("ends with\r\n2 line breaks\r\n\r\n", "test: |+\n ends with\n 2 line breaks\n")]
83+
[InlineData("ends with\r\n3 line breaks\r\n\r\n\r\n", "test: |+\n ends with\n 3 line breaks\n\n")]
84+
[InlineData(" starts with\nspaces", "test: |-2\n starts with\n spaces")]
85+
[InlineData(" starts with\nspaces, and ends with line break\n", "test: |2\n starts with\n spaces, and ends with line break")]
86+
[InlineData("contains\n\n\nempty lines", "test: |-\n contains\n\n\n empty lines")]
8587
[InlineData("no line breaks fallback ", "test: 'no line breaks fallback '")]
8688
public void WriteStringWithNewlineCharactersInObjectAsYamlWorks(string input, string expected)
8789
{
@@ -103,11 +105,13 @@ public void WriteStringWithNewlineCharactersInObjectAsYamlWorks(string input, st
103105
}
104106

105107
[Theory]
106-
[InlineData("multiline\r\nstring", "- |\n multiline\n string")]
107-
[InlineData("ends with\r\nline break\r\n", "- |+\n ends with\n line break")]
108-
[InlineData(" starts with\nspaces", "- |2\n starts with\n spaces")]
109-
[InlineData(" starts with\nspaces, and ends with line break\n", "- |+2\n starts with\n spaces, and ends with line break")]
110-
[InlineData("contains\n\n\nempty lines", "- |\n contains\n\n\n empty lines")]
108+
[InlineData("multiline\r\nstring", "- |-\n multiline\n string")]
109+
[InlineData("ends with\r\nline break\r\n", "- |\n ends with\n line break")]
110+
[InlineData("ends with\r\n2 line breaks\r\n\r\n", "- |+\n ends with\n 2 line breaks\n")]
111+
[InlineData("ends with\r\n3 line breaks\r\n\r\n\r\n", "- |+\n ends with\n 3 line breaks\n\n")]
112+
[InlineData(" starts with\nspaces", "- |-2\n starts with\n spaces")]
113+
[InlineData(" starts with\nspaces, and ends with line break\n", "- |2\n starts with\n spaces, and ends with line break")]
114+
[InlineData("contains\n\n\nempty lines", "- |-\n contains\n\n\n empty lines")]
111115
[InlineData("no line breaks fallback ", "- 'no line breaks fallback '")]
112116
public void WriteStringWithNewlineCharactersInArrayAsYamlWorks(string input, string expected)
113117
{

0 commit comments

Comments
 (0)