fix(parsing): fold an explicit key ending at its value colon
A plain scalar continuation that ends at a `:` is normally a new implicit mapping key, so the scalar stops before it. Under an explicit key (`? foo` then `bar :`) the `:` is the key's own value indicator instead, so the line is still key content. The scalar dropped that line and the parser stalled, so `? foo` then `bar : baz` failed rather than yielding the key `foo bar`. When the explicit-key marker is pending, fold the continuation line in and stop, leaving the `:` to be scanned as the value indicator. An implicit key keeps the previous behaviour, so a continuation ending at `:` still begins a new key. The test-suite rates are unchanged, since no comparable case isolates the block form and the flow form needs separate explicit-key work, but block explicit keys spanning lines now fold correctly. 466 tests pass.
This commit is contained in:
parent
8bc855d7a0
commit
143624be08
@ -84,6 +84,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Fixed
|
||||
|
||||
- An explicit key (`? foo`) whose plain scalar spans lines now folds a continuation line that ends at
|
||||
the value `:`. `? foo` then `bar : baz` is the key `foo bar`, not an error: the `:` is the key's
|
||||
value indicator, so the line stays key content and folds in, where before the scalar dropped it and
|
||||
the parser stalled. An implicit key is unchanged, since there a continuation line ending at `:` is a
|
||||
new mapping key and the scalar still stops before it. The block test-suite rates are unchanged (no
|
||||
comparable case isolates this), and the flow form needs separate explicit-key work, but the parser
|
||||
now folds block explicit keys correctly.
|
||||
|
||||
- An explicit block scalar indentation indicator (`|2`, `>1`) on an inline mapping value now measures
|
||||
from the mapping's indentation. A value like `- aaa: |2` has the inline mapping as its parent, but
|
||||
that mapping sits at an implicit indentation off the main stack, so the indicator was added to the
|
||||
|
||||
@ -170,7 +170,17 @@ extension PureYAML.Parsing.Scanner {
|
||||
var continuationState = state
|
||||
continuationState.reader = probe
|
||||
let continuation = scanPlainScalarContinuationLine(&continuationState)
|
||||
guard !isAtMappingValueIndicator(state: continuationState) else {
|
||||
if isAtMappingValueIndicator(state: continuationState) {
|
||||
// A continuation line ending at `:` is normally a new implicit key, so the scalar
|
||||
// stops before it. Under an explicit key (`? foo` then `bar :`), the `:` is the key's
|
||||
// value indicator instead, so the line is still key content: fold it in and stop, and
|
||||
// the `:` is scanned next as the value indicator.
|
||||
guard state.pendingExplicitKey else {
|
||||
return value
|
||||
}
|
||||
state = continuationState
|
||||
value += blankLineCount == 0 ? " " : String(repeating: "\n", count: blankLineCount)
|
||||
value += continuation
|
||||
return value
|
||||
}
|
||||
|
||||
|
||||
33
Tests/ExplicitKeyMultilineFoldTests.swift
Normal file
33
Tests/ExplicitKeyMultilineFoldTests.swift
Normal file
@ -0,0 +1,33 @@
|
||||
@testable import PureYAML
|
||||
import Testing
|
||||
|
||||
/// An explicit key (`? foo`) may span lines: its plain scalar folds across the break, and a `:` on
|
||||
/// the last key line is the value indicator, not a new entry. Under an implicit key a continuation
|
||||
/// line ending at `:` is instead a new mapping key, so the scalar stops before it, unchanged.
|
||||
@Suite("Explicit key multiline fold")
|
||||
struct ExplicitKeyMultilineFoldTests {
|
||||
@Test("An explicit key folds a continuation line that ends at the value colon")
|
||||
func test_continuationEndingAtColon() throws {
|
||||
#expect(try PureYAML.parse("? foo\n bar : baz\n") == .mapping(.init([
|
||||
.init(key: "foo bar", value: .string("baz")),
|
||||
])))
|
||||
}
|
||||
|
||||
@Test("An explicit key with the colon on its own line still folds")
|
||||
func test_colonOnOwnLine() throws {
|
||||
#expect(try PureYAML.parse("? foo\n bar\n: baz\n") == .mapping(.init([
|
||||
.init(key: "foo bar", value: .string("baz")),
|
||||
])))
|
||||
}
|
||||
|
||||
@Test("An implicit key is unaffected: a continuation ending at a colon stays a new key")
|
||||
func test_implicitKeyUnchanged() throws {
|
||||
#expect(try PureYAML.parse("foo: bar\n") == .mapping(.init([
|
||||
.init(key: "foo", value: .string("bar")),
|
||||
])))
|
||||
#expect(try PureYAML.parse("a: 1\nb: 2\n") == .mapping(.init([
|
||||
.init(key: "a", value: .int(1)),
|
||||
.init(key: "b", value: .int(2)),
|
||||
])))
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user