Skip to content

Commit e5b7b1a

Browse files
Add IDictionary type converter
Add a new type converter for IDictionary types which unwraps PScustomObjects before serializing. Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
1 parent 9eeee79 commit e5b7b1a

4 files changed

Lines changed: 73 additions & 2 deletions

File tree

Tests/powershell-yaml.Tests.ps1

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ InModuleScope $moduleName {
2929
$compareStrictly = Get-EquivalencyOption -Comparator Equality
3030

3131
Describe "Test PSCustomObject wrapped values are serialized correctly" {
32-
Context "Wrapped values" {
32+
Context "A PSCustomObject containing nested PSCustomObjects" {
3333
It "Should serialize correctly" {
3434
$expectBigInt = [System.Numerics.BigInteger]::Parse("9999999999999999999999999999999999999999999999999")
3535
$obj = [PSCustomObject]@{a = Write-Output 'string'; b = Write-Output 1; c = Write-Output @{nested = $true};d = [pscustomobject]$expectBigInt}
@@ -41,6 +41,37 @@ InModuleScope $moduleName {
4141
Assert-Equivalent -Options $compareStrictly -Expected $expectBigInt -Actual $fromYaml["d"]
4242
}
4343
}
44+
45+
Context "A hashtable containing nested PSCustomObjects" {
46+
It "Should serialize correctly" {
47+
$expectBigInt = [System.Numerics.BigInteger]::Parse("9999999999999999999999999999999999999999999999999")
48+
$obj = @{a = Write-Output 'string'; b = Write-Output 1; c = Write-Output @{nested = $true};d = [pscustomobject]$expectBigInt}
49+
$asYaml = ConvertTo-Yaml $obj
50+
$fromYaml = ConvertFrom-Yaml $asYaml
51+
52+
Assert-Equivalent -Options $compareStrictly -Expected "string" -Actual $fromYaml["a"]
53+
Assert-Equivalent -Options $compareStrictly -Expected 1 -Actual $fromYaml["b"]
54+
Assert-Equivalent -Options $compareStrictly -Expected $expectBigInt -Actual $fromYaml["d"]
55+
}
56+
}
57+
58+
Context "A generic dictionary containing nested PSCustomObjects" {
59+
It "Should serialize correctly" {
60+
$expectBigInt = [System.Numerics.BigInteger]::Parse("9999999999999999999999999999999999999999999999999")
61+
$obj = [System.Collections.Generic.Dictionary[string, object]]::new()
62+
$obj["a"] = Write-Output 'string'
63+
$obj["b"] = Write-Output 1
64+
$obj["c"] = Write-Output @{nested = $true}
65+
$obj["d"] = [pscustomobject]$expectBigInt
66+
67+
$asYaml = ConvertTo-Yaml $obj
68+
$fromYaml = ConvertFrom-Yaml $asYaml
69+
70+
Assert-Equivalent -Options $compareStrictly -Expected "string" -Actual $fromYaml["a"]
71+
Assert-Equivalent -Options $compareStrictly -Expected 1 -Actual $fromYaml["b"]
72+
Assert-Equivalent -Options $compareStrictly -Expected $expectBigInt -Actual $fromYaml["d"]
73+
}
74+
}
4475
}
4576

4677
Describe "Test encode-decode symmetry." {
512 Bytes
Binary file not shown.
512 Bytes
Binary file not shown.

src/PowerShellYamlSerializer.cs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,46 @@ public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerialize
4949
}
5050
}
5151

52+
public class IDictionaryTypeConverter : IYamlTypeConverter {
53+
54+
private bool omitNullValues;
55+
56+
public IDictionaryTypeConverter(bool omitNullValues = false) {
57+
this.omitNullValues = omitNullValues;
58+
}
59+
60+
public bool Accepts(Type type) {
61+
return typeof(IDictionary).IsAssignableFrom(type);
62+
}
63+
64+
public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) {
65+
var deserializedObject = rootDeserializer(typeof(IDictionary<string, object>)) as IDictionary;
66+
return deserializedObject;
67+
}
68+
69+
public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer) {
70+
var hObj = (IDictionary)value;
71+
emitter.Emit(new MappingStart());
72+
foreach (DictionaryEntry entry in hObj) {
73+
if(entry.Value == null) {
74+
if (this.omitNullValues == true) {
75+
continue;
76+
}
77+
serializer(entry.Key, entry.Key.GetType());
78+
emitter.Emit(new Scalar(AnchorName.Empty, "tag:yaml.org,2002:null", "", ScalarStyle.Plain, true, false));
79+
continue;
80+
}
81+
serializer(entry.Key, entry.Key.GetType());
82+
if (entry.Value is PSObject nestedObj) {
83+
serializer(nestedObj.BaseObject, nestedObj.BaseObject.GetType());
84+
} else {
85+
serializer(entry.Value, entry.Value.GetType());
86+
}
87+
}
88+
emitter.Emit(new MappingEnd());
89+
}
90+
}
91+
5292
public class PSObjectTypeConverter : IYamlTypeConverter {
5393

5494
private bool omitNullValues;
@@ -70,7 +110,6 @@ public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeseria
70110

71111
public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer) {
72112
var psObj = (PSObject)value;
73-
74113
emitter.Emit(new MappingStart());
75114
foreach (var prop in psObj.Properties) {
76115
if (prop.Value == null) {
@@ -161,6 +200,7 @@ public static SerializerBuilder BuildSerializer(
161200
builder = builder
162201
.WithEventEmitter(next => new StringQuotingEmitter(next))
163202
.WithTypeConverter(new BigIntegerTypeConverter())
203+
.WithTypeConverter(new IDictionaryTypeConverter(omitNullValues))
164204
.WithTypeConverter(new PSObjectTypeConverter(omitNullValues));
165205
if (omitNullValues == true) {
166206
builder = builder

0 commit comments

Comments
 (0)