Skip to content

Commit

Permalink
Add IDictionary type converter
Browse files Browse the repository at this point in the history
Add a new type converter for IDictionary types which unwraps PScustomObjects
before serializing.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
  • Loading branch information
gabriel-samfira committed Dec 15, 2024
1 parent 9eeee79 commit e5b7b1a
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 2 deletions.
33 changes: 32 additions & 1 deletion Tests/powershell-yaml.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ InModuleScope $moduleName {
$compareStrictly = Get-EquivalencyOption -Comparator Equality

Describe "Test PSCustomObject wrapped values are serialized correctly" {
Context "Wrapped values" {
Context "A PSCustomObject containing nested PSCustomObjects" {
It "Should serialize correctly" {
$expectBigInt = [System.Numerics.BigInteger]::Parse("9999999999999999999999999999999999999999999999999")
$obj = [PSCustomObject]@{a = Write-Output 'string'; b = Write-Output 1; c = Write-Output @{nested = $true};d = [pscustomobject]$expectBigInt}
Expand All @@ -41,6 +41,37 @@ InModuleScope $moduleName {
Assert-Equivalent -Options $compareStrictly -Expected $expectBigInt -Actual $fromYaml["d"]
}
}

Context "A hashtable containing nested PSCustomObjects" {
It "Should serialize correctly" {
$expectBigInt = [System.Numerics.BigInteger]::Parse("9999999999999999999999999999999999999999999999999")
$obj = @{a = Write-Output 'string'; b = Write-Output 1; c = Write-Output @{nested = $true};d = [pscustomobject]$expectBigInt}
$asYaml = ConvertTo-Yaml $obj
$fromYaml = ConvertFrom-Yaml $asYaml

Assert-Equivalent -Options $compareStrictly -Expected "string" -Actual $fromYaml["a"]
Assert-Equivalent -Options $compareStrictly -Expected 1 -Actual $fromYaml["b"]
Assert-Equivalent -Options $compareStrictly -Expected $expectBigInt -Actual $fromYaml["d"]
}
}

Context "A generic dictionary containing nested PSCustomObjects" {
It "Should serialize correctly" {
$expectBigInt = [System.Numerics.BigInteger]::Parse("9999999999999999999999999999999999999999999999999")
$obj = [System.Collections.Generic.Dictionary[string, object]]::new()
$obj["a"] = Write-Output 'string'
$obj["b"] = Write-Output 1
$obj["c"] = Write-Output @{nested = $true}
$obj["d"] = [pscustomobject]$expectBigInt

$asYaml = ConvertTo-Yaml $obj
$fromYaml = ConvertFrom-Yaml $asYaml

Assert-Equivalent -Options $compareStrictly -Expected "string" -Actual $fromYaml["a"]
Assert-Equivalent -Options $compareStrictly -Expected 1 -Actual $fromYaml["b"]
Assert-Equivalent -Options $compareStrictly -Expected $expectBigInt -Actual $fromYaml["d"]
}
}
}

Describe "Test encode-decode symmetry." {
Expand Down
Binary file modified lib/net47/PowerShellYamlSerializer.dll
Binary file not shown.
Binary file modified lib/netstandard2.1/PowerShellYamlSerializer.dll
Binary file not shown.
42 changes: 41 additions & 1 deletion src/PowerShellYamlSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,46 @@ public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerialize
}
}

public class IDictionaryTypeConverter : IYamlTypeConverter {

private bool omitNullValues;

public IDictionaryTypeConverter(bool omitNullValues = false) {
this.omitNullValues = omitNullValues;
}

public bool Accepts(Type type) {
return typeof(IDictionary).IsAssignableFrom(type);
}

public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) {
var deserializedObject = rootDeserializer(typeof(IDictionary<string, object>)) as IDictionary;
return deserializedObject;
}

public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer) {
var hObj = (IDictionary)value;
emitter.Emit(new MappingStart());
foreach (DictionaryEntry entry in hObj) {
if(entry.Value == null) {
if (this.omitNullValues == true) {
continue;
}
serializer(entry.Key, entry.Key.GetType());
emitter.Emit(new Scalar(AnchorName.Empty, "tag:yaml.org,2002:null", "", ScalarStyle.Plain, true, false));
continue;
}
serializer(entry.Key, entry.Key.GetType());
if (entry.Value is PSObject nestedObj) {
serializer(nestedObj.BaseObject, nestedObj.BaseObject.GetType());
} else {
serializer(entry.Value, entry.Value.GetType());
}
}
emitter.Emit(new MappingEnd());
}
}

public class PSObjectTypeConverter : IYamlTypeConverter {

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

public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer) {
var psObj = (PSObject)value;

emitter.Emit(new MappingStart());
foreach (var prop in psObj.Properties) {
if (prop.Value == null) {
Expand Down Expand Up @@ -161,6 +200,7 @@ public static SerializerBuilder BuildSerializer(
builder = builder
.WithEventEmitter(next => new StringQuotingEmitter(next))
.WithTypeConverter(new BigIntegerTypeConverter())
.WithTypeConverter(new IDictionaryTypeConverter(omitNullValues))
.WithTypeConverter(new PSObjectTypeConverter(omitNullValues));
if (omitNullValues == true) {
builder = builder
Expand Down

0 comments on commit e5b7b1a

Please sign in to comment.