|
2 | 2 | using System.Collections.Generic; |
3 | 3 | using System.Globalization; |
4 | 4 | using System.Linq; |
| 5 | +using System.Text.Json; |
5 | 6 | using System.Text.Json.Nodes; |
6 | 7 | using SharpYaml; |
7 | 8 | using SharpYaml.Serialization; |
@@ -110,30 +111,54 @@ private static YamlSequenceNode ToYamlSequence(this JsonArray arr) |
110 | 111 | return new YamlSequenceNode(arr.Select(x => x!.ToYamlNode())); |
111 | 112 | } |
112 | 113 |
|
| 114 | + private static readonly HashSet<string> YamlNullRepresentations = new(StringComparer.Ordinal) |
| 115 | + { |
| 116 | + "~", |
| 117 | + "null", |
| 118 | + "Null", |
| 119 | + "NULL" |
| 120 | + }; |
| 121 | + |
113 | 122 | private static JsonValue ToJsonValue(this YamlScalarNode yaml) |
114 | 123 | { |
115 | | - switch (yaml.Style) |
| 124 | + return yaml.Style switch |
116 | 125 | { |
117 | | - case ScalarStyle.Plain: |
118 | | - return decimal.TryParse(yaml.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var d) |
119 | | - ? JsonValue.Create(d) |
120 | | - : bool.TryParse(yaml.Value, out var b) |
121 | | - ? JsonValue.Create(b) |
122 | | - : JsonValue.Create(yaml.Value)!; |
123 | | - case ScalarStyle.SingleQuoted: |
124 | | - case ScalarStyle.DoubleQuoted: |
125 | | - case ScalarStyle.Literal: |
126 | | - case ScalarStyle.Folded: |
127 | | - case ScalarStyle.Any: |
128 | | - return JsonValue.Create(yaml.Value)!; |
129 | | - default: |
130 | | - throw new ArgumentOutOfRangeException(); |
131 | | - } |
| 126 | + ScalarStyle.Plain when decimal.TryParse(yaml.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var d) => JsonValue.Create(d), |
| 127 | + ScalarStyle.Plain when bool.TryParse(yaml.Value, out var b) => JsonValue.Create(b), |
| 128 | + ScalarStyle.Plain when YamlNullRepresentations.Contains(yaml.Value) => (JsonValue)JsonNullSentinel.JsonNull.DeepClone(), |
| 129 | + ScalarStyle.Plain => JsonValue.Create(yaml.Value), |
| 130 | + ScalarStyle.SingleQuoted or ScalarStyle.DoubleQuoted or ScalarStyle.Literal or ScalarStyle.Folded or ScalarStyle.Any => JsonValue.Create(yaml.Value), |
| 131 | + _ => throw new ArgumentOutOfRangeException(nameof(yaml)), |
| 132 | + }; |
132 | 133 | } |
133 | 134 |
|
134 | 135 | private static YamlScalarNode ToYamlScalar(this JsonValue val) |
135 | 136 | { |
136 | | - return new YamlScalarNode(val.ToJsonString()); |
| 137 | + // Try to get the underlying value based on its actual type |
| 138 | + // First try to get it as a string |
| 139 | + if (val.GetValueKind() == JsonValueKind.String && |
| 140 | + val.TryGetValue(out string? stringValue)) |
| 141 | + { |
| 142 | + // For string values, we need to determine if they should be quoted in YAML |
| 143 | + // Strings that look like numbers, booleans, or null need to be quoted |
| 144 | + // to preserve their string type when round-tripping |
| 145 | + var needsQuoting = decimal.TryParse(stringValue, NumberStyles.Float, CultureInfo.InvariantCulture, out _) || |
| 146 | + bool.TryParse(stringValue, out _) || |
| 147 | + YamlNullRepresentations.Contains(stringValue); |
| 148 | + |
| 149 | + return new YamlScalarNode(stringValue) |
| 150 | + { |
| 151 | + Style = needsQuoting ? ScalarStyle.DoubleQuoted : ScalarStyle.Plain |
| 152 | + }; |
| 153 | + } |
| 154 | + |
| 155 | + // For non-string values (numbers, booleans, null), use their string representation |
| 156 | + // These should remain unquoted in YAML |
| 157 | + var valueString = val.ToString(); |
| 158 | + return new YamlScalarNode(valueString) |
| 159 | + { |
| 160 | + Style = ScalarStyle.Plain |
| 161 | + }; |
137 | 162 | } |
138 | 163 | } |
139 | 164 | } |
0 commit comments