Skip to content

Commit f100e2d

Browse files
Merge pull request #166 from gabriel-samfira/fix-json-compatibility
Fix broken json compatibility
2 parents 352d6b0 + 59300ff commit f100e2d

File tree

5 files changed

+119
-10
lines changed

5 files changed

+119
-10
lines changed

Tests/powershell-yaml.Tests.ps1

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,99 @@ Import-Module $modulePath
2828
InModuleScope $moduleName {
2929
$compareStrictly = Get-EquivalencyOption -Comparator Equality
3030

31+
Describe "Test flow styles" {
32+
Context "Mappings, sequences and PSCustomObjects" {
33+
It "Should serialize Block flow (default) correctly" {
34+
$obj = [ordered]@{
35+
aStringKey = "test"
36+
anIntKey = 1
37+
anArrayKey = @(1, 2, 3)
38+
}
39+
$expected = @"
40+
aStringKey: test
41+
anIntKey: 1
42+
anArrayKey:
43+
- 1
44+
- 2
45+
- 3
46+
47+
"@
48+
$serialized = ConvertTo-Yaml $obj
49+
Assert-Equivalent -Options $compareStrictly -Expected $expected -Actual $serialized
50+
51+
$pso = [pscustomobject]$obj
52+
$serialized = ConvertTo-Yaml $pso
53+
Assert-Equivalent -Options $compareStrictly -Expected $expected -Actual $serialized
54+
}
55+
56+
It "Should serialize Flow flow correctly" {
57+
$obj = [ordered]@{
58+
aStringKey = "test"
59+
anIntKey = 1
60+
anArrayKey = @(1, 2, 3)
61+
}
62+
$expected = @"
63+
{aStringKey: test, anIntKey: 1, anArrayKey: [1, 2, 3]}
64+
65+
"@
66+
$serialized = ConvertTo-Yaml -Options UseFlowStyle $obj
67+
Assert-Equivalent -Options $compareStrictly -Expected $expected -Actual $serialized
68+
69+
$pso = [pscustomobject]$obj
70+
$serialized = ConvertTo-Yaml -Options UseFlowStyle $pso
71+
Assert-Equivalent -Options $compareStrictly -Expected $expected -Actual $serialized
72+
}
73+
74+
It "Should serialize SequenceFlowStyle correctly" {
75+
$obj = [ordered]@{
76+
aStringKey = "test"
77+
anIntKey = 1
78+
anArrayKey = @(1, 2, 3)
79+
}
80+
$expected = @"
81+
aStringKey: test
82+
anIntKey: 1
83+
anArrayKey: [1, 2, 3]
84+
85+
"@
86+
$serialized = ConvertTo-Yaml -Options UseSequenceFlowStyle $obj
87+
Assert-Equivalent -Options $compareStrictly -Expected $expected -Actual $serialized
88+
89+
$pso = [pscustomobject]$obj
90+
$serialized = ConvertTo-Yaml -Options UseSequenceFlowStyle $pso
91+
Assert-Equivalent -Options $compareStrictly -Expected $expected -Actual $serialized
92+
}
93+
94+
It "Should serialize JsonCompatible correctly" {
95+
$obj = [ordered]@{
96+
aStringKey = "test"
97+
anIntKey = 1
98+
anArrayKey = @(1, 2, 3)
99+
}
100+
$expected = @"
101+
{"aStringKey": "test", "anIntKey": 1, "anArrayKey": [1, 2, 3]}
102+
103+
"@
104+
$serialized = ConvertTo-Yaml -Options JsonCompatible $obj
105+
Assert-Equivalent -Options $compareStrictly -Expected $expected -Actual $serialized
106+
107+
if ($PSVersionTable['PSEdition'] -eq 'Core') {
108+
$deserializedWithJSonCommandlet = $serialized | ConvertFrom-Json -AsHashtable
109+
Assert-Equivalent -Options $compareStrictly -Expected $obj -Actual $deserializedWithJSonCommandlet
110+
}
111+
112+
$pso = [pscustomobject]$obj
113+
$serialized = ConvertTo-Yaml -Options JsonCompatible $pso
114+
Assert-Equivalent -Options $compareStrictly -Expected $expected -Actual $serialized
115+
116+
if ($PSVersionTable['PSEdition'] -eq 'Core') {
117+
$deserializedWithJSonCommandlet = $serialized | ConvertFrom-Json -AsHashtable
118+
Assert-Equivalent -Options $compareStrictly -Expected $obj -Actual $deserializedWithJSonCommandlet
119+
}
120+
}
121+
}
122+
}
123+
31124
Describe "Test PSCustomObject wrapped values are serialized correctly" {
32125
Context "A PSCustomObject containing nested PSCustomObjects" {
33126
It "Should serialize correctly" {
512 Bytes
Binary file not shown.
512 Bytes
Binary file not shown.

powershell-yaml.psm1

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,8 @@ function Get-Serializer {
392392
)
393393

394394
$builder = $yamlDotNetAssembly.GetType("YamlDotNet.Serialization.SerializerBuilder")::new()
395-
395+
$JsonCompatible = $Options.HasFlag([SerializationOptions]::JsonCompatible)
396+
396397
if ($Options.HasFlag([SerializationOptions]::Roundtrip)) {
397398
$builder = $builder.EnsureRoundtrip()
398399
}
@@ -402,7 +403,7 @@ function Get-Serializer {
402403
if ($Options.HasFlag([SerializationOptions]::EmitDefaults)) {
403404
$builder = $builder.EmitDefaults()
404405
}
405-
if ($Options.HasFlag([SerializationOptions]::JsonCompatible)) {
406+
if ($JsonCompatible) {
406407
$builder = $builder.JsonCompatible()
407408
}
408409
if ($Options.HasFlag([SerializationOptions]::DefaultToStaticType)) {
@@ -418,7 +419,7 @@ function Get-Serializer {
418419
$useSequenceFlowStyle = $Options.HasFlag([SerializationOptions]::UseSequenceFlowStyle)
419420

420421
$stringQuoted = $stringQuotedAssembly.GetType("BuilderUtils")
421-
$builder = $stringQuoted::BuildSerializer($builder, $omitNull, $useFlowStyle, $useSequenceFlowStyle)
422+
$builder = $stringQuoted::BuildSerializer($builder, $omitNull, $useFlowStyle, $useSequenceFlowStyle, $JsonCompatible)
422423

423424
return $builder.Build()
424425
}

src/PowerShellYamlSerializer.cs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using YamlDotNet.Serialization;
99
using YamlDotNet.Serialization.EventEmitters;
1010
using YamlDotNet.Core.Events;
11+
using YamlDotNet.Serialization.NamingConventions;
1112
using YamlDotNet.Serialization.ObjectGraphVisitors;
1213

1314
public sealed class NullValueGraphVisitor : ChainedObjectGraphVisitor
@@ -52,9 +53,11 @@ public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerialize
5253
public class IDictionaryTypeConverter : IYamlTypeConverter {
5354

5455
private bool omitNullValues;
56+
private bool useFlowStyle;
5557

56-
public IDictionaryTypeConverter(bool omitNullValues = false) {
58+
public IDictionaryTypeConverter(bool omitNullValues = false, bool useFlowStyle = false) {
5759
this.omitNullValues = omitNullValues;
60+
this.useFlowStyle = useFlowStyle;
5861
}
5962

6063
public bool Accepts(Type type) {
@@ -68,7 +71,9 @@ public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeseria
6871

6972
public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer) {
7073
var hObj = (IDictionary)value;
71-
emitter.Emit(new MappingStart());
74+
var mappingStyle = this.useFlowStyle ? MappingStyle.Flow : MappingStyle.Block;
75+
76+
emitter.Emit(new MappingStart(AnchorName.Empty, TagName.Empty, true, mappingStyle));
7277
foreach (DictionaryEntry entry in hObj) {
7378
if(entry.Value == null) {
7479
if (this.omitNullValues == true) {
@@ -92,9 +97,11 @@ public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerialize
9297
public class PSObjectTypeConverter : IYamlTypeConverter {
9398

9499
private bool omitNullValues;
100+
private bool useFlowStyle;
95101

96-
public PSObjectTypeConverter(bool omitNullValues = false) {
102+
public PSObjectTypeConverter(bool omitNullValues = false, bool useFlowStyle = false) {
97103
this.omitNullValues = omitNullValues;
104+
this.useFlowStyle = useFlowStyle;
98105
}
99106

100107
public bool Accepts(Type type) {
@@ -110,7 +117,8 @@ public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeseria
110117

111118
public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer) {
112119
var psObj = (PSObject)value;
113-
emitter.Emit(new MappingStart());
120+
var mappingStyle = this.useFlowStyle ? MappingStyle.Flow : MappingStyle.Block;
121+
emitter.Emit(new MappingStart(AnchorName.Empty, TagName.Empty, true, mappingStyle));
114122
foreach (var prop in psObj.Properties) {
115123
if (prop.Value == null) {
116124
if (this.omitNullValues == true) {
@@ -196,12 +204,19 @@ public static SerializerBuilder BuildSerializer(
196204
SerializerBuilder builder,
197205
bool omitNullValues = false,
198206
bool useFlowStyle = false,
199-
bool useSequenceFlowStyle = false) {
207+
bool useSequenceFlowStyle = false,
208+
bool jsonCompatible = false) {
209+
210+
if (jsonCompatible == true) {
211+
useFlowStyle = true;
212+
useSequenceFlowStyle = true;
213+
}
214+
200215
builder = builder
201216
.WithEventEmitter(next => new StringQuotingEmitter(next))
202217
.WithTypeConverter(new BigIntegerTypeConverter())
203-
.WithTypeConverter(new IDictionaryTypeConverter(omitNullValues))
204-
.WithTypeConverter(new PSObjectTypeConverter(omitNullValues));
218+
.WithTypeConverter(new IDictionaryTypeConverter(omitNullValues, useFlowStyle))
219+
.WithTypeConverter(new PSObjectTypeConverter(omitNullValues, useFlowStyle));
205220
if (omitNullValues == true) {
206221
builder = builder
207222
.WithEmissionPhaseObjectGraphVisitor(args => new NullValueGraphVisitor(args.InnerVisitor));

0 commit comments

Comments
 (0)