Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions src/SharpYaml.Tests/EmitterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
Expand Down Expand Up @@ -306,5 +307,46 @@ public void FoldedStylePreservesNewLines()
Dump.WriteLine(output);
Assert.AreEqual(input, output);
}

[Test]
public void FoldedScalarWithMultipleWordsPreservesLineBreaks()
{
// The real issue is not that "a folded\nscalar" should become "a folded scalar"
// in terms of content (that's actually correct YAML behavior)
// The issue is that when emitting a scalar with newlines as a folded scalar,
// it should preserve the newlines in the YAML structure

var input = "a folded\nscalar";

// When we emit a scalar with embedded newlines as a folded scalar,
// it should be emitted as:
// >-
// a folded
// scalar
// NOT as:
// >-
// a folded scalar

var yaml = EmitScalar(new Scalar(null, null, input, ScalarStyle.Folded, true, false));
Console.WriteLine("Emitted YAML:");
Console.WriteLine(yaml);

// The emitted YAML should contain the folded scalar structure
Assert.That(yaml, Does.Contain(">-"), "Should emit as folded scalar");
Assert.That(yaml, Does.Contain("a folded"), "Should contain the first part");
Assert.That(yaml, Does.Contain("scalar"), "Should contain the second part");

// Parse it back and verify the content is preserved
var stream = new YamlStream();
stream.Load(new StringReader(yaml));
var sequence = (YamlSequenceNode)stream.Documents[0].RootNode;
var scalar = (YamlScalarNode)sequence.Children[0];

Console.WriteLine($"Original: '{input}'");
Console.WriteLine($"Round-trip result: '{scalar.Value}'");

// This should pass - the content should be preserved
Assert.AreEqual(input, scalar.Value, "Folded scalar content should be preserved during round-trip");
}
}
}
42 changes: 39 additions & 3 deletions src/SharpYaml/Emitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -546,14 +546,28 @@ private void AnalyzeScalar(string value)
scalarData.isSingleQuotedAllowed = false;
}

if (space_break || special_characters)
if (space_break)
{
scalarData.isFlowPlainAllowed = false;
scalarData.isBlockPlainAllowed = false;
scalarData.isSingleQuotedAllowed = false;
scalarData.isBlockAllowed = false;
}

if (special_characters)
{
scalarData.isFlowPlainAllowed = false;
scalarData.isBlockPlainAllowed = false;
scalarData.isSingleQuotedAllowed = false;
// Don't disable block scalars for line breaks - they're the point of folded/literal scalars
// However, disable block scalars for single-character strings containing only special characters
// as they're better represented with quoted styles
if (!line_breaks || (line_breaks && value.Length == 1))
{
scalarData.isBlockAllowed = false;
}
}

if (line_breaks)
{
scalarData.isFlowPlainAllowed = false;
Expand Down Expand Up @@ -1520,10 +1534,25 @@ private void SelectScalarStyle(ParsingEvent evt)

if (style == ScalarStyle.Literal || style == ScalarStyle.Folded)
{
if (!scalarData.isBlockAllowed || flowLevel != 0 || isSimpleKeyContext)
// Only override block styles if they're truly not possible to emit
// Don't override if the user explicitly requested Folded/Literal style
// unless we're in a context where block scalars are impossible (flow context, simple key)
if (flowLevel != 0 || isSimpleKeyContext)
{
style = ScalarStyle.DoubleQuoted;
}
// For both literal and folded scalars, fall back to double quotes if block scalars aren't allowed
else if (!scalarData.isBlockAllowed)
{
style = ScalarStyle.DoubleQuoted;
}
}

// Final fallback: if no style is allowed, always use double quoted
if (!scalarData.isFlowPlainAllowed && !scalarData.isBlockPlainAllowed &&
!scalarData.isSingleQuotedAllowed && !scalarData.isBlockAllowed)
{
style = ScalarStyle.DoubleQuoted;
}

// TODO: What is this code supposed to mean?
Expand All @@ -1532,6 +1561,13 @@ private void SelectScalarStyle(ParsingEvent evt)
// tagData.handle = "!";
//}

// Final fallback: if no style is allowed, always use double quoted
if (!scalarData.isFlowPlainAllowed && !scalarData.isBlockPlainAllowed &&
!scalarData.isSingleQuotedAllowed && !scalarData.isBlockAllowed)
{
style = ScalarStyle.DoubleQuoted;
}

scalarData.style = style;
}

Expand All @@ -1545,7 +1581,7 @@ private void EmitAlias()
}

/// <summary>
/// Write an achor.
/// Write an anchor.
/// </summary>
private void ProcessAnchor()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ internal class PrimitiveSerializer : ScalarSerializerBase, IYamlSerializableFact
{
throw new YamlException(scalar.Start, scalar.End, $"Unable to decode char from [{text}]. Expecting a string of length == 1");
}
return text.ToCharArray()[0];
return text[0];
case TypeCode.Byte:
return byte.Parse(text, CultureInfo.InvariantCulture);
case TypeCode.SByte:
Expand Down