Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow setting the newline character when serializing #747

Merged
merged 2 commits into from
Dec 1, 2022
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
54 changes: 54 additions & 0 deletions YamlDotNet.Test/Serialization/SerializationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,60 @@ public void SerializeCustomTags()
result.Should().Be(expectedResult);
}

[Fact]
public void SerializeWithCRLFNewLine()
{
var expectedResult = Yaml
.ReaderFrom("list.yaml")
.ReadToEnd()
.NormalizeNewLines()
.Replace(Environment.NewLine, "\r\n");

var list = new string[] {"one", "two", "three"};
var result = SerializerBuilder
.WithNewLine("\r\n")
.Build()
.Serialize(list);

result.Should().Be(expectedResult);
}

[Fact]
public void SerializeWithLFNewLine()
{
var expectedResult = Yaml
.ReaderFrom("list.yaml")
.ReadToEnd()
.NormalizeNewLines()
.Replace(Environment.NewLine, "\n");

var list = new string[] {"one", "two", "three"};
var result = SerializerBuilder
.WithNewLine("\n")
.Build()
.Serialize(list);

result.Should().Be(expectedResult);
}

[Fact]
public void SerializeWithCRNewLine()
{
var expectedResult = Yaml
.ReaderFrom("list.yaml")
.ReadToEnd()
.NormalizeNewLines()
.Replace(Environment.NewLine, "\r");

var list = new string[] {"one", "two", "three"};
var result = SerializerBuilder
.WithNewLine("\r")
.Build()
.Serialize(list);

result.Should().Be(expectedResult);
}

[Fact]
public void DeserializeExplicitType()
{
Expand Down
2 changes: 1 addition & 1 deletion YamlDotNet.Test/files/list.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
- one
- two
- three
- three
4 changes: 3 additions & 1 deletion YamlDotNet/Core/Emitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public class Emitter : IEmitter
private bool isWhitespace;
private bool isIndentation;
private readonly bool forceIndentLess;
private readonly string newLine;

private bool isDocumentEndWritten;

Expand Down Expand Up @@ -147,6 +148,7 @@ public Emitter(TextWriter output, EmitterSettings settings)
this.maxSimpleKeyLength = settings.MaxSimpleKeyLength;
this.skipAnchorName = settings.SkipAnchorName;
this.forceIndentLess = !settings.IndentSequences;
this.newLine = settings.NewLine;

this.output = output;
this.outputUsesUnicodeEncoding = IsUnicode(output.Encoding);
Expand Down Expand Up @@ -1917,7 +1919,7 @@ private void WriteBreak(char breakCharacter = '\n')
{
if (breakCharacter == '\n')
{
output.WriteLine();
output.Write(newLine);
}
else
{
Expand Down
40 changes: 34 additions & 6 deletions YamlDotNet/Core/EmitterSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ public sealed class EmitterSettings
/// </summary>
public int BestWidth { get; } = int.MaxValue;

/// <summary>
/// New line characters.
/// </summary>
public string NewLine { get; } = Environment.NewLine;

/// <summary>
/// If true, write the output in canonical form.
/// </summary>
Expand Down Expand Up @@ -64,7 +69,7 @@ public EmitterSettings()
{
}

public EmitterSettings(int bestIndent, int bestWidth, bool isCanonical, int maxSimpleKeyLength, bool skipAnchorName = false, bool indentSequences = false)
public EmitterSettings(int bestIndent, int bestWidth, bool isCanonical, int maxSimpleKeyLength, bool skipAnchorName = false, bool indentSequences = false, string? newLine = null)
{
if (bestIndent < 2 || bestIndent > 9)
{
Expand All @@ -87,6 +92,7 @@ public EmitterSettings(int bestIndent, int bestWidth, bool isCanonical, int maxS
MaxSimpleKeyLength = maxSimpleKeyLength;
SkipAnchorName = skipAnchorName;
IndentSequences = indentSequences;
NewLine = newLine ?? Environment.NewLine;
}

public EmitterSettings WithBestIndent(int bestIndent)
Expand All @@ -96,7 +102,9 @@ public EmitterSettings WithBestIndent(int bestIndent)
BestWidth,
IsCanonical,
MaxSimpleKeyLength,
SkipAnchorName
SkipAnchorName,
IndentSequences,
NewLine
);
}

Expand All @@ -107,7 +115,9 @@ public EmitterSettings WithBestWidth(int bestWidth)
bestWidth,
IsCanonical,
MaxSimpleKeyLength,
SkipAnchorName
SkipAnchorName,
IndentSequences,
NewLine
);
}

Expand All @@ -118,7 +128,22 @@ public EmitterSettings WithMaxSimpleKeyLength(int maxSimpleKeyLength)
BestWidth,
IsCanonical,
maxSimpleKeyLength,
SkipAnchorName
SkipAnchorName,
IndentSequences,
NewLine
);
}

public EmitterSettings WithNewLine(string newLine)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to include NewLine in the other With methods, otherwise, it'll get lost if another With method is called after the WithNewLine

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, great - I'll figure it out - Thx

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be pretty simple, it looks like that same thing was missed for the indented sequences.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, as I went through the file, I saw that indentSequences was suffering from the same problem, as in if invoking any other "With" method after having applied indentSequences, it would discard the previously applied value. I'm not sure how to isolate this in a separate pull request, since it's a CTOR invocation, and the newLine value is after the indentSequences value in the CTOR arguments. Anyways, I've pushed now, including the fix for indentSequences ...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing the indent at the same time. Looks like the Canonical method was missed though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is one method, but it only allows for setting it to true. will you merge this in anyways? I guess it's an unrelated issue ...?

Screenshot 2022-12-01 at 8 20 15 AM

If you're merging, when can we have a new release? I need the NuGet package in our own stuff ...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cut releases right after merging in. You should see a new package up on nuget in a few minutes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thx Edward, you're a champ ^_^

{
return new EmitterSettings(
BestIndent,
BestWidth,
IsCanonical,
MaxSimpleKeyLength,
SkipAnchorName,
IndentSequences,
newLine
);
}

Expand All @@ -140,7 +165,9 @@ public EmitterSettings WithoutAnchorName()
BestWidth,
IsCanonical,
MaxSimpleKeyLength,
true
true,
IndentSequences,
NewLine
);
}

Expand All @@ -152,7 +179,8 @@ public EmitterSettings WithIndentedSequences()
IsCanonical,
MaxSimpleKeyLength,
SkipAnchorName,
true
true,
NewLine
);
}
}
Expand Down
10 changes: 10 additions & 0 deletions YamlDotNet/Serialization/SerializerBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,16 @@ public SerializerBuilder JsonCompatible()
.WithEventEmitter(inner => new JsonEventEmitter(inner), loc => loc.InsteadOf<TypeAssigningEventEmitter>());
}

/// <summary>
/// Allows you to override the new line character to use when serializing to YAML.
/// </summary>
/// <param name="newLine">NewLine character(s) to use when serializing to YAML.</param>
public SerializerBuilder WithNewLine(string newLine)
{
this.emitterSettings = this.emitterSettings.WithNewLine(newLine);
return this;
}

/// <summary>
/// Registers an additional <see cref="IObjectGraphVisitor{Nothing}" /> to be used by the serializer
/// before emitting an object graph.
Expand Down