aaubry / YamlDotNet

YamlDotNet is a .NET library for YAML
MIT License
2.48k stars 466 forks source link

Better serialization of strings that look like integers (specifically, octals) #934

Closed fiotti closed 1 day ago

fiotti commented 2 weeks ago

Is your feature request related to a problem? Please describe. All values are treated as strings, but numeric strings are not escaped, example:

ISerializer serializer = new SerializerBuilder().Build();
serializer.Serialize(new { Test = "1234" }); // output: "Test: 1234\r\n"

I think this does not directly violate YAML specs, but according to YAML specs, plain (unquoted) scalars may be interpreted in special ways. By serializing in this format we lost the information that the value was originally a string, now it looks more like an integer.

This might not be a big problem for most strings, but YAML specs gives an example of an octal number as a sequence of digits with a leading 0, as an example, the YAML value 014 is interpreted as "14 octal", which is 12.

serializer.Serialize(new { Test = "01234" }); // output: "Test: 01234\r\n"

Describe the solution you'd like A more versatile approach would be to add quotes to strings that look like numbers.

serializer.Serialize(new { Test = "hello" }); // output: "Test: hello\r\n"
serializer.Serialize(new { Test = "01234" }); // output: "Test: '01234'\r\n"

Describe alternatives you've considered I considered using a custom YamlFormatter, but there is no FormatAsString() method exposed, so this is not a viable solution.

I ended up wrapping in a custom QuotedString class all the strings that look like numbers, then using a custom IYamlTypeConverter to emit a Scalar with ScalarStyle.SingleQuoted.

Additional context In my specific case I'm passing the output YAML to Helm, which interprets that 01234 value as the integer value 668 instead of as the string '01234', breaking some functionalities.

Thank you!

EdwardCooke commented 1 day ago

Try using withquotenecessarystrings on your serializerbuilder. That should automatically add quotes around scalars that are numbers only. Along with other special values.

fiotti commented 1 day ago

Using WithAttemptingUnquotedStringTypeDeserialization() during deserialization and WithQuoteNecessaryStrings() during serialization does indeed solve the issue.

Thanks! I had completely missed it 😅