cloudbase / powershell-yaml

PowerShell CmdLets for YAML format manipulation
Apache License 2.0
434 stars 78 forks source link

Handle large numbers and PSCustomObjects #135

Closed gabriel-samfira closed 3 months ago

gabriel-samfira commented 3 months ago

This change fixes the way powershell-yaml deals with two particular types: really large numbers and PSCustomObjects.

When an integer larger than what an int64 could handle was deserialized, powershell-yaml would convert it to scientific notation. This is default behavior in powershell when you try to cast a number larger than [int64]::MaxValue to an [int64]. This change attempts to cast all numbers to [BigInteger] and then try to fit that value into the smallest possible type. If that is not possible, we leave it as [BigInteger].

This change also adds a custom type converter that properly serializes a [BigInteger] back to yaml.

Another type we've had issues with is the PSCustomObject type. This change adds a custom type converter for that as well and removes the hack we had to do to cast the PSCustomObject to a dictionary before we serialize it.

A final change made here was in the way the assembly we ship is built. The code was separated into a proper project and is built using the dotnet sdk.

Fixes: #128 Fixes: #106

gabriel-samfira commented 3 months ago

Demo of the change:

PS /home/gabriel/powershell-yaml> $yaml = @"                         
>> ---
>> bigInt: 999999999999999999999999999999999
>> double: 1.21
>> bigIntWithTag: !!int 9999999999999999999999999
>> anInt: 11
>> aDouble: 1111111111111111
>> "@
PS /home/gabriel/powershell-yaml> $converted = ConvertFrom-Yaml $yaml
PS /home/gabriel/powershell-yaml> $converted.bigIntWithTag.GetType() 

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     BigInteger                               System.ValueType

PS /home/gabriel/powershell-yaml> $converted.bigInt.GetType()       

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     BigInteger                               System.ValueType

PS /home/gabriel/powershell-yaml> $converted.double.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Double                                   System.ValueType

PS /home/gabriel/powershell-yaml> $converted.anInt.GetType() 

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Int32                                    System.ValueType

PS /home/gabriel/powershell-yaml> $converted.aDouble.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Int64                                    System.ValueType

PS /home/gabriel/powershell-yaml> $converted

Name                           Value
----                           -----
aDouble                        1111111111111111
anInt                          11
bigInt                         999999999999999999999999999999999
double                         1.21
bigIntWithTag                  9999999999999999999999999

PS /home/gabriel/powershell-yaml> $converted | ConvertTo-Yaml        
bigIntWithTag: 9999999999999999999999999
bigInt: 999999999999999999999999999999999
anInt: 11
aDouble: 1111111111111111
double: 1.21