Skip to content

Commit 810adde

Browse files
Emit explicit overlong mapping keys
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent edd0130 commit 810adde

4 files changed

Lines changed: 83 additions & 2 deletions

File tree

src/functions/private/ConvertTo-YamlFlowText.ps1

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,13 @@ function ConvertTo-YamlFlowText {
132132
continue
133133
}
134134
if ($frame.State -eq 'MappingValue') {
135-
$frame.Parts.Add("$($frame.KeyText)`: $($frame.Child.Value)")
135+
$keyNode = $frame.Node.Entries[$frame.Index].Key
136+
$explicitKey = (
137+
Get-YamlEmissionImplicitKeyLength -Node $keyNode `
138+
-RenderedText $frame.KeyText
139+
) -gt 1024
140+
$keyPrefix = if ($explicitKey) { '? ' } else { '' }
141+
$frame.Parts.Add("$keyPrefix$($frame.KeyText)`: $($frame.Child.Value)")
136142
$frame.Index++
137143
$frame.State = 'MappingKey'
138144
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
function Get-YamlEmissionImplicitKeyLength {
2+
<#
3+
.SYNOPSIS
4+
Gets an emitted implicit key length in Unicode scalar values.
5+
#>
6+
[CmdletBinding()]
7+
[OutputType([int])]
8+
param (
9+
[Parameter(Mandatory)]
10+
[pscustomobject] $Node,
11+
12+
[Parameter(Mandatory)]
13+
[string] $RenderedText
14+
)
15+
16+
if ($Node.Kind.Equals('Scalar', [System.StringComparison]::Ordinal)) {
17+
return Get-YamlRuneCount -Text ([string] $Node.Value)
18+
}
19+
return Get-YamlRuneCount -Text $RenderedText
20+
}

src/functions/private/Write-YamlNodeText.ps1

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,20 @@ function Write-YamlNodeText {
4545
if ($task.Type -eq 'Entry') {
4646
$keyText = ConvertTo-YamlFlowText -Node $task.Entry.Key `
4747
-EmittedReferences $EmittedReferences
48+
$explicitKey = (
49+
Get-YamlEmissionImplicitKeyLength -Node $task.Entry.Key `
50+
-RenderedText $keyText
51+
) -gt 1024
52+
if ($explicitKey) {
53+
$spaces = ' ' * ($task.Level * $Indent)
54+
[void] $Builder.Append($spaces).Append('? ').Append($keyText).Append("`n")
55+
}
4856
$stack.Push([pscustomobject]@{
4957
Type = 'Node'
5058
Node = $task.Entry.Value
5159
Entry = $null
5260
Level = $task.Level
53-
LeadingText = "$keyText`: "
61+
LeadingText = if ($explicitKey) { ': ' } else { "$keyText`: " }
5462
})
5563
continue
5664
}

tests/ConvertTo-Yaml.Tests.ps1

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,53 @@ Describe 'ConvertTo-Yaml' {
261261
$enumerator.Value | Should -Be 'value'
262262
}
263263

264+
It 'uses explicit keys when scalar keys exceed 1024 Unicode values' {
265+
$atLimit = [System.Collections.Specialized.OrderedDictionary]::new()
266+
$atLimit.Add(('x' * 1024), 'value')
267+
$overLimit = [System.Collections.Specialized.OrderedDictionary]::new()
268+
$overLimit.Add(('😀' * 1025), [ordered]@{ nested = 'value' })
269+
270+
$atLimitYaml = ConvertTo-Yaml -InputObject $atLimit
271+
$overLimitYaml = ConvertTo-Yaml -InputObject $overLimit
272+
$roundTrip = $overLimitYaml | ConvertFrom-Yaml -AsHashtable
273+
274+
$atLimitYaml | Should -Not -Match '^\? '
275+
$overLimitYaml | Should -Match '^\? '
276+
$overLimitYaml | Should -Match '(?m)^: $'
277+
($overLimitYaml | Test-Yaml) | Should -BeTrue
278+
$roundTrip.Contains(('😀' * 1025)) | Should -BeTrue
279+
$roundTrip[('😀' * 1025)]['nested'] | Should -Be 'value'
280+
}
281+
282+
It 'uses explicit keys when rendered collection keys exceed 1024 values' {
283+
$dictionary = [System.Collections.Specialized.OrderedDictionary]::new()
284+
$key = [object[]] (0..299)
285+
$dictionary.Add($key, 'value')
286+
287+
$yaml = ConvertTo-Yaml -InputObject $dictionary
288+
$roundTrip = $yaml | ConvertFrom-Yaml -AsHashtable
289+
$enumerator = $roundTrip.GetEnumerator()
290+
$null = $enumerator.MoveNext()
291+
292+
$yaml | Should -Match '^\? \['
293+
($yaml | Test-Yaml) | Should -BeTrue
294+
$enumerator.Key | Should -Be $key
295+
$enumerator.Value | Should -Be 'value'
296+
}
297+
298+
It 'uses explicit keys inside flow-rendered complex keys' {
299+
$innerKey = [System.Collections.Specialized.OrderedDictionary]::new()
300+
$innerKey.Add(('x' * 1025), 'inner')
301+
$dictionary = [System.Collections.Specialized.OrderedDictionary]::new()
302+
$dictionary.Add($innerKey, 'outer')
303+
304+
$yaml = ConvertTo-Yaml -InputObject $dictionary
305+
306+
$yaml | Should -Match '\{\? '
307+
($yaml | Test-Yaml) | Should -BeTrue
308+
{ $yaml | ConvertFrom-Yaml -AsHashtable } | Should -Not -Throw
309+
}
310+
264311
It 'rejects dictionary keys that normalize to the same YAML value' {
265312
$dictionary = [System.Collections.Specialized.OrderedDictionary]::new()
266313
$dictionary.Add([int] 1, 'int')

0 commit comments

Comments
 (0)