Skip to content

Commit 8956c19

Browse files
Fix mapping key parsing: preserve raw text without type resolution, use [pscustomobject] cast to handle member name collisions
- Keys like true/false/null/~ are now preserved as literal strings instead of being type-resolved then cast back (which changed true->True, null->empty string) - Quoted keys still have their escapes expanded correctly - Replace Add-Member loop with [pscustomobject]$map cast to avoid errors when keys collide with built-in member names like ToString/GetType - Add 3 tests: YAML-special keys, quoted key escapes, member name collision keys
1 parent b4113eb commit 8956c19

2 files changed

Lines changed: 53 additions & 10 deletions

File tree

src/functions/private/ConvertFrom-YamlMapping.ps1

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,42 +30,45 @@
3030
throw "ConvertFrom-Yaml: expected mapping key at line $($line.Number): '$($line.Content)'."
3131
}
3232

33-
$key = ConvertFrom-YamlScalar -Raw $line.Content.Substring(0, $colonIdx).Trim()
33+
$rawKey = $line.Content.Substring(0, $colonIdx).Trim()
34+
if ($rawKey.Length -ge 2 -and $rawKey[0] -eq "'" -and $rawKey[-1] -eq "'") {
35+
$key = ($rawKey.Substring(1, $rawKey.Length - 2)) -replace "''", "'"
36+
} elseif ($rawKey.Length -ge 2 -and $rawKey[0] -eq '"' -and $rawKey[-1] -eq '"') {
37+
$key = Expand-YamlDoubleQuoted -Text ($rawKey.Substring(1, $rawKey.Length - 2))
38+
} else {
39+
$key = $rawKey
40+
}
3441
$rest = $line.Content.Substring($colonIdx + 1).Trim()
3542

3643
$Context.Index++
3744

3845
if ($rest.Length -gt 0) {
39-
$map[[string]$key] = ConvertFrom-YamlScalar -Raw $rest
46+
$map[$key] = ConvertFrom-YamlScalar -Raw $rest
4047
continue
4148
}
4249

4350
# Value on subsequent indented lines (mapping or sequence) or null.
4451
if ($Context.Index -ge $lines.Count) {
45-
$map[[string]$key] = $null
52+
$map[$key] = $null
4653
continue
4754
}
4855

4956
$next = $lines[$Context.Index]
5057
if ($next.Indent -le $Indent) {
51-
$map[[string]$key] = $null
58+
$map[$key] = $null
5259
continue
5360
}
5461

5562
# Sequences are allowed to start at the same indent as the parent key in YAML.
5663
# We require the child to be indented strictly greater than the key here for clarity.
5764
$childIndent = $next.Indent
5865
$value = ConvertFrom-YamlNode -Context $Context -Indent $childIndent -Depth ($Depth + 1)
59-
$map[[string]$key] = $value
66+
$map[$key] = $value
6067
}
6168

6269
if ($Context.AsHashtable) {
6370
return $map
6471
}
6572

66-
$obj = [pscustomobject]@{}
67-
foreach ($k in $map.Keys) {
68-
Add-Member -InputObject $obj -MemberType NoteProperty -Name $k -Value $map[$k]
69-
}
70-
return $obj
73+
return [pscustomobject]$map
7174
}

tests/ConvertFrom-Yaml.Tests.ps1

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,46 @@ mango: 3
131131
$names[1] | Should -Be 'apple'
132132
$names[2] | Should -Be 'mango'
133133
}
134+
135+
It 'Preserves raw text of YAML-special keys without type resolution' {
136+
$yaml = @'
137+
true: a
138+
false: b
139+
null: c
140+
~: d
141+
'@
142+
$result = $yaml | ConvertFrom-Yaml -AsHashtable
143+
$result.Keys | Should -Contain 'true'
144+
$result.Keys | Should -Contain 'false'
145+
$result.Keys | Should -Contain 'null'
146+
$result.Keys | Should -Contain '~'
147+
$result['true'] | Should -Be 'a'
148+
$result['false'] | Should -Be 'b'
149+
$result['null'] | Should -Be 'c'
150+
$result['~'] | Should -Be 'd'
151+
}
152+
153+
It 'Handles quoted mapping keys with escapes' {
154+
$yaml = @'
155+
"key\nwith": value1
156+
'single''s': value2
157+
'@
158+
$result = $yaml | ConvertFrom-Yaml -AsHashtable
159+
$result.Keys | Should -Contain "key`nwith"
160+
$result["key`nwith"] | Should -Be 'value1'
161+
$result.Keys | Should -Contain "single's"
162+
$result["single's"] | Should -Be 'value2'
163+
}
164+
165+
It 'Parses keys that collide with built-in member names' {
166+
$yaml = @'
167+
ToString: hello
168+
GetType: world
169+
'@
170+
$result = $yaml | ConvertFrom-Yaml
171+
$result.PSObject.Properties['ToString'].Value | Should -Be 'hello'
172+
$result.PSObject.Properties['GetType'].Value | Should -Be 'world'
173+
}
134174
}
135175

136176
Context 'Sequences' {

0 commit comments

Comments
 (0)