Private/Write-Toon.ps1
|
function Write-Toon { param( [object]$Value, [int]$IndentSize = 2, [string]$KeyFolding = 'off', [int]$FlattenDepth = [int]::MaxValue, [int]$Depth = 0, [string]$Key = $null ) $indent = ' ' * ($Depth * $IndentSize) if ($Value -is [string]) { # Treat string as primitive return Write-Primitive -Value $Value -Delimiter ',' } elseif ($Value -is [System.Collections.IList]) { # Array $length = $Value.Count $isUniformObjects = Test-UniformObject -Array $Value $headerKey = if ($Key) { "$Key" } else { "" } if ($isUniformObjects) { # Tabular $fields = Get-ObjectField -Object $Value[0] $fieldList = $fields -join ',' $header = "${headerKey}[$length]{$fieldList}:" $lines = @($header) foreach ($item in $Value) { $row = @() foreach ($field in $fields) { $row += Write-Primitive -Value $item[$field] -Delimiter ',' } $lines += ($row -join ',') } return $lines -join "`n" } else { # Mixed array $header = "${headerKey}[$length]:" $lines = @($header) foreach ($item in $Value) { $encodedItem = Write-Toon -Value $item -IndentSize $IndentSize -KeyFolding $KeyFolding -FlattenDepth $FlattenDepth -Depth ($Depth + 1) $lines += "- $encodedItem" } return ($lines -join "`n").Replace("`n", "`n$indent") } } elseif ($Value -is [System.Collections.IDictionary]) { # Object $lines = @() foreach ($k in $Value.Keys) { $val = $Value[$k] if ($val -is [System.Collections.IList] -and (Test-UniformObject -Array $val)) { # Tabular array $lines += Write-Toon -Value $val -IndentSize $IndentSize -KeyFolding $KeyFolding -FlattenDepth $FlattenDepth -Depth $Depth -Key $k } else { $lines += "${k}: $(Write-Primitive -Value $val -Delimiter ',')" } } return $lines -join "`n" } else { # Primitive if ($Key) { return "$Key`: $(Write-Primitive -Value $Value -Delimiter ',')" } else { return Write-Primitive -Value $Value -Delimiter ',' } } } function Test-UniformObject { param([System.Collections.IList]$Array) if ($Array.Count -eq 0) { return $false } $first = $Array[0] if (-not ($first -is [System.Collections.IDictionary])) { return $false } $fields = Get-ObjectField -Object $first foreach ($item in $Array) { if (-not ($item -is [System.Collections.IDictionary])) { return $false } $itemFields = Get-ObjectField -Object $item if ($fields.Count -ne $itemFields.Count -or (Compare-Object $fields $itemFields)) { return $false } } return $true } function Get-ObjectField { param([System.Collections.IDictionary]$Object) return $Object.Keys | Sort-Object } function Write-Primitive { param([object]$Value, [string]$Delimiter = ',') if ($null -eq $Value) { return 'null' } if ($Value -is [bool]) { return $Value.ToString().ToLower() } if ($Value -is [string]) { if (Test-QuoteString -String $Value -Delimiter $Delimiter) { return "`"$($Value.Replace('\', '\\').Replace('"', '\"').Replace("`n", '\n').Replace("`r", '\r').Replace("`t", '\t'))`"" } else { return $Value } } if ($Value -is [double] -or $Value -is [int] -or $Value -is [long]) { return $Value.ToString() } return $Value.ToString() } function Test-QuoteString { param([string]$String, [string]$Delimiter) if ($String -eq '') { return $true } if ($String -match '^\s|\s$') { return $true } if ($String -in @('true', 'false', 'null')) { return $true } if ($String -match '^-|^-.*') { return $true } if ($String -match '[:\[\]{}' + [regex]::Escape($Delimiter) + '\n\r\t\\]') { return $true } if ($String -match '^0\d+$') { return $true } if ($String -match '^-?\d+(\.\d+)?([eE][+-]?\d+)?$') { return $true } return $false } |