Skip to content

Commit 9c0aafb

Browse files
Fix quote tracking in Find-YamlMappingColon and Remove-YamlInlineComment for plain scalars
Quote characters inside plain (unquoted) scalars were incorrectly toggling quote state, causing colon detection and inline comment stripping to fail for values like owner's: Bob or name: O'Connor # comment. Added inPlain flag to both functions so quote characters only open quoted regions at token boundaries (position 0, after ': ', after '- '), not mid-token in plain scalars. Added 5 tests covering apostrophe/double-quote in plain keys, values, and sequence items with inline comments.
1 parent f3e279e commit 9c0aafb

3 files changed

Lines changed: 73 additions & 5 deletions

File tree

src/functions/private/Find-YamlMappingColon.ps1

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
66
.DESCRIPTION
77
The colon must be followed by whitespace or end-of-line for it to be a YAML mapping
8-
separator. Colons inside quoted strings are ignored.
8+
separator. Colons inside quoted strings are ignored. Quote characters inside plain
9+
(unquoted) scalars are treated as literal characters and do not toggle quote state.
910
#>
1011
[CmdletBinding()]
1112
[OutputType([int])]
@@ -17,16 +18,30 @@
1718

1819
$inSingle = $false
1920
$inDouble = $false
21+
$inPlain = $false
2022
for ($i = 0; $i -lt $Content.Length; $i++) {
2123
$c = $Content[$i]
2224
if ($c -eq '\' -and $inDouble) { $i++; continue }
23-
if ($c -eq "'" -and -not $inDouble) { $inSingle = -not $inSingle; continue }
24-
if ($c -eq '"' -and -not $inSingle) { $inDouble = -not $inDouble; continue }
25+
if ($c -eq "'" -and -not $inDouble) {
26+
if ($inSingle) { $inSingle = $false; continue }
27+
if (-not $inPlain) { $inSingle = $true; continue }
28+
continue
29+
}
30+
if ($c -eq '"' -and -not $inSingle) {
31+
if ($inDouble) { $inDouble = $false; continue }
32+
if (-not $inPlain) { $inDouble = $true; continue }
33+
continue
34+
}
2535
if ($c -eq ':' -and -not $inSingle -and -not $inDouble) {
2636
if ($i -eq $Content.Length - 1) { return $i }
2737
$next = $Content[$i + 1]
2838
if ($next -eq ' ' -or $next -eq "`t") { return $i }
2939
}
40+
if (-not $inSingle -and -not $inDouble -and -not $inPlain) {
41+
if ($c -ne ' ' -and $c -ne "`t") {
42+
$inPlain = $true
43+
}
44+
}
3045
}
3146
return -1
3247
}

src/functions/private/Remove-YamlInlineComment.ps1

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
$inSingle = $false
1717
$inDouble = $false
18+
$inPlain = $false
1819
for ($i = 0; $i -lt $Line.Length; $i++) {
1920
$c = $Line[$i]
2021
if ($c -eq '\' -and $inDouble) {
@@ -23,11 +24,13 @@
2324
continue
2425
}
2526
if ($c -eq "'" -and -not $inDouble) {
26-
$inSingle = -not $inSingle
27+
if ($inSingle) { $inSingle = $false; continue }
28+
if (-not $inPlain) { $inSingle = $true; continue }
2729
continue
2830
}
2931
if ($c -eq '"' -and -not $inSingle) {
30-
$inDouble = -not $inDouble
32+
if ($inDouble) { $inDouble = $false; continue }
33+
if (-not $inPlain) { $inDouble = $true; continue }
3134
continue
3235
}
3336
if ($c -eq '#' -and -not $inSingle -and -not $inDouble) {
@@ -36,6 +39,24 @@
3639
return $Line.Substring(0, $i)
3740
}
3841
}
42+
# Track plain scalar vs token boundary.
43+
if (-not $inSingle -and -not $inDouble -and -not $inPlain) {
44+
if ($c -ne ' ' -and $c -ne "`t") {
45+
# A '- ' sequence dash is a token boundary, not a plain scalar start.
46+
if ($c -eq '-' -and $i + 1 -lt $Line.Length -and $Line[$i + 1] -eq ' ') {
47+
# sequence dash — value after '- ' may be quoted; do not enter plain
48+
} else {
49+
$inPlain = $true
50+
}
51+
}
52+
}
53+
# Reset $inPlain after mapping separator ': ' to allow value-position quotes.
54+
if ($c -eq ':' -and -not $inSingle -and -not $inDouble -and $i + 1 -lt $Line.Length) {
55+
$next = $Line[$i + 1]
56+
if ($next -eq ' ' -or $next -eq "`t") {
57+
$inPlain = $false
58+
}
59+
}
3960
}
4061
return $Line
4162
}

tests/ConvertFrom-Yaml.Tests.ps1

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,4 +670,36 @@ key: value
670670
{ $yaml | ConvertFrom-Yaml } | Should -Throw '*tab*'
671671
}
672672
}
673+
674+
Context 'Plain scalars with embedded quotes' {
675+
It 'Parses a plain key containing an apostrophe before the colon' {
676+
$result = "owner's: Bob" | ConvertFrom-Yaml
677+
$result."owner's" | Should -Be 'Bob'
678+
}
679+
680+
It 'Parses a plain value containing an apostrophe with inline comment stripped' {
681+
$result = "name: O'Connor # a comment" | ConvertFrom-Yaml
682+
$result.name | Should -Be "O'Connor"
683+
}
684+
685+
It 'Parses a plain key with embedded double-quote before the colon' {
686+
$result = 'say"hello: world' | ConvertFrom-Yaml
687+
$result.'say"hello' | Should -Be 'world'
688+
}
689+
690+
It 'Strips inline comment when value contains a mid-token double-quote' {
691+
$result = 'key: val"ue # comment' | ConvertFrom-Yaml
692+
$result.key | Should -Be 'val"ue'
693+
}
694+
695+
It 'Parses sequence items with apostrophe in plain scalar and inline comment' {
696+
$yaml = @'
697+
- it's fine # comment
698+
- also's good
699+
'@
700+
$result = $yaml | ConvertFrom-Yaml -NoEnumerate
701+
$result[0] | Should -Be "it's fine"
702+
$result[1] | Should -Be "also's good"
703+
}
704+
}
673705
}

0 commit comments

Comments
 (0)