|
5 | 5 |
|
6 | 6 | .DESCRIPTION |
7 | 7 | Recursively converts a PowerShell object (hashtable, array, PSCustomObject, or primitive) |
8 | | - into a Lua table string. This is the internal serialization engine used by ConvertTo-Lua. |
| 8 | + into a Lua table constructor string. This is the internal serialization engine used by ConvertTo-Lua. |
| 9 | +
|
| 10 | + Uses fixed 4-space indentation per the Lua community convention. |
| 11 | + Properties with $null values are omitted (Lua nil-means-absent semantics). |
9 | 12 | #> |
10 | 13 | [OutputType([string])] |
11 | 14 | [CmdletBinding()] |
|
15 | 18 | [AllowNull()] |
16 | 19 | [object] $InputObject, |
17 | 20 |
|
18 | | - # The current indentation depth for formatting. |
| 21 | + # The current recursion depth. |
19 | 22 | [Parameter()] |
20 | | - [int] $Depth = 0, |
| 23 | + [int] $CurrentDepth = 0, |
21 | 24 |
|
22 | | - # Number of spaces per indentation level. |
| 25 | + # Maximum allowed recursion depth. |
23 | 26 | [Parameter()] |
24 | | - [int] $IndentSize = 4, |
| 27 | + [int] $MaxDepth = 2, |
25 | 28 |
|
26 | 29 | # Whether to compress the output (no newlines or indentation). |
27 | 30 | [Parameter()] |
28 | | - [switch] $Compress |
| 31 | + [switch] $Compress, |
| 32 | + |
| 33 | + # Serialize enum values as their string name instead of numeric value. |
| 34 | + [Parameter()] |
| 35 | + [switch] $EnumsAsStrings |
29 | 36 | ) |
30 | 37 |
|
31 | 38 | begin { |
32 | | - $indent = if ($Compress) { '' } else { ' ' * ($IndentSize * $Depth) } |
33 | | - $childIndent = if ($Compress) { '' } else { ' ' * ($IndentSize * ($Depth + 1)) } |
| 39 | + $indent = if ($Compress) { '' } else { ' ' * (4 * $CurrentDepth) } |
| 40 | + $childIndent = if ($Compress) { '' } else { ' ' * (4 * ($CurrentDepth + 1)) } |
34 | 41 | $newline = if ($Compress) { '' } else { "`n" } |
35 | 42 | $separator = if ($Compress) { ',' } else { ",`n" } |
36 | 43 | } |
|
48 | 55 | } |
49 | 56 | } |
50 | 57 |
|
| 58 | + # Enum handling |
| 59 | + if ($InputObject -is [enum]) { |
| 60 | + if ($EnumsAsStrings) { |
| 61 | + $escaped = $InputObject.ToString() -replace '\\', '\\\\' -replace '"', '\"' |
| 62 | + return "`"$escaped`"" |
| 63 | + } |
| 64 | + return ([int]$InputObject).ToString([System.Globalization.CultureInfo]::InvariantCulture) |
| 65 | + } |
| 66 | + |
51 | 67 | if ($InputObject -is [int] -or $InputObject -is [long] -or |
52 | | - $InputObject -is [float] -or $InputObject -is [double] -or |
53 | | - $InputObject -is [decimal] -or $InputObject -is [int16] -or |
54 | | - $InputObject -is [int64] -or $InputObject -is [uint16] -or |
55 | | - $InputObject -is [uint32] -or $InputObject -is [uint64] -or |
56 | | - $InputObject -is [byte] -or $InputObject -is [sbyte] -or |
57 | | - $InputObject -is [single]) { |
| 68 | + $InputObject -is [int16] -or $InputObject -is [int64] -or |
| 69 | + $InputObject -is [uint16] -or $InputObject -is [uint32] -or |
| 70 | + $InputObject -is [uint64] -or $InputObject -is [byte] -or |
| 71 | + $InputObject -is [sbyte]) { |
| 72 | + return $InputObject.ToString([System.Globalization.CultureInfo]::InvariantCulture) |
| 73 | + } |
| 74 | + |
| 75 | + if ($InputObject -is [float] -or $InputObject -is [double] -or |
| 76 | + $InputObject -is [decimal] -or $InputObject -is [single]) { |
58 | 77 | return $InputObject.ToString([System.Globalization.CultureInfo]::InvariantCulture) |
59 | 78 | } |
60 | 79 |
|
61 | 80 | if ($InputObject -is [string]) { |
62 | | - $escaped = $InputObject -replace '\\', '\\' -replace '"', '\"' -replace "`n", '\n' -replace "`r", '\r' -replace "`t", '\t' |
| 81 | + $escaped = $InputObject -replace '\\', '\\' -replace '"', '\"' -replace "`0", '\0' -replace "`a", '\a' -replace "`b", '\b' -replace "`f", '\f' -replace "`n", '\n' -replace "`r", '\r' -replace "`t", '\t' -replace "`v", '\v' |
63 | 82 | return "`"$escaped`"" |
64 | 83 | } |
65 | 84 |
|
| 85 | + # Depth check for complex types |
| 86 | + if ($CurrentDepth -ge $MaxDepth) { |
| 87 | + Write-Warning "Depth limit ($MaxDepth) exceeded at depth $CurrentDepth. Serializing remaining object as string." |
| 88 | + $str = $InputObject.ToString() -replace '\\', '\\\\' -replace '"', '\"' |
| 89 | + return "`"$str`"" |
| 90 | + } |
| 91 | + |
66 | 92 | if ($InputObject -is [System.Collections.IList]) { |
67 | 93 | if ($InputObject.Count -eq 0) { |
68 | 94 | return '{}' |
69 | 95 | } |
70 | 96 | $items = [System.Collections.Generic.List[string]]::new() |
71 | 97 | foreach ($item in $InputObject) { |
72 | | - $value = ConvertTo-LuaTable -InputObject $item -Depth ($Depth + 1) -IndentSize $IndentSize -Compress:$Compress |
| 98 | + $value = ConvertTo-LuaTable -InputObject $item -CurrentDepth ($CurrentDepth + 1) -MaxDepth $MaxDepth -Compress:$Compress -EnumsAsStrings:$EnumsAsStrings |
73 | 99 | $items.Add("$childIndent$value") |
74 | 100 | } |
75 | 101 | return "{$newline$($items -join $separator)$newline$indent}" |
|
82 | 108 | } |
83 | 109 | $entries = [System.Collections.Generic.List[string]]::new() |
84 | 110 | foreach ($key in $InputObject.Keys) { |
85 | | - $value = ConvertTo-LuaTable -InputObject $InputObject[$key] -Depth ($Depth + 1) -IndentSize $IndentSize -Compress:$Compress |
| 111 | + $val = $InputObject[$key] |
| 112 | + # Omit $null values per Lua nil-means-absent semantics |
| 113 | + if ($null -eq $val) { |
| 114 | + continue |
| 115 | + } |
| 116 | + $value = ConvertTo-LuaTable -InputObject $val -CurrentDepth ($CurrentDepth + 1) -MaxDepth $MaxDepth -Compress:$Compress -EnumsAsStrings:$EnumsAsStrings |
86 | 117 | $luaKey = Format-LuaKey -Key ([string]$key) |
87 | 118 | $space = if ($Compress) { '' } else { ' ' } |
88 | 119 | $entries.Add("$childIndent$luaKey$space=${space}$value") |
89 | 120 | } |
| 121 | + if ($entries.Count -eq 0) { |
| 122 | + return '{}' |
| 123 | + } |
90 | 124 | return "{$newline$($entries -join $separator)$newline$indent}" |
91 | 125 | } |
92 | 126 |
|
93 | | - # Handle PSCustomObject (from ConvertFrom-Json etc.) |
| 127 | + # Handle PSCustomObject |
94 | 128 | if ($InputObject -is [psobject]) { |
95 | 129 | $properties = $InputObject.PSObject.Properties | Where-Object { $_.MemberType -eq 'NoteProperty' } |
96 | 130 | if (-not $properties) { |
97 | 131 | return '{}' |
98 | 132 | } |
99 | 133 | $entries = [System.Collections.Generic.List[string]]::new() |
100 | 134 | foreach ($prop in $properties) { |
101 | | - $value = ConvertTo-LuaTable -InputObject $prop.Value -Depth ($Depth + 1) -IndentSize $IndentSize -Compress:$Compress |
| 135 | + # Omit $null values per Lua nil-means-absent semantics |
| 136 | + if ($null -eq $prop.Value) { |
| 137 | + continue |
| 138 | + } |
| 139 | + $value = ConvertTo-LuaTable -InputObject $prop.Value -CurrentDepth ($CurrentDepth + 1) -MaxDepth $MaxDepth -Compress:$Compress -EnumsAsStrings:$EnumsAsStrings |
102 | 140 | $luaKey = Format-LuaKey -Key $prop.Name |
103 | 141 | $space = if ($Compress) { '' } else { ' ' } |
104 | 142 | $entries.Add("$childIndent$luaKey$space=${space}$value") |
105 | 143 | } |
| 144 | + if ($entries.Count -eq 0) { |
| 145 | + return '{}' |
| 146 | + } |
106 | 147 | return "{$newline$($entries -join $separator)$newline$indent}" |
107 | 148 | } |
108 | 149 |
|
|
0 commit comments