fix(parsing): end a root block scalar at a document marker
A `---` or `...` at column 0 ends an active block scalar rather than being consumed as its content. The scanner now closes the scalar's indentation at the marker, dedenting back to the document level, so the token stream stays balanced: the dedent precedes the documentEnd. Previously the scalar's indent lingered past the marker and surfaced as a stray late dedent plus a phantom empty document, and a following directive was misread as a scalar. Fixes suite case W4TN (parse-level conformance 315 -> 316); adds tests.
This commit is contained in:
parent
056095ca3d
commit
8112954f4c
@ -11,6 +11,22 @@ extension PureYAML.Parsing.Scanner {
|
||||
let end = state.reader.mark
|
||||
let current = state.indentation.last ?? 0
|
||||
let wasInBlockScalar = state.blockScalarIndentation != nil
|
||||
|
||||
// A document marker (`---` / `...`) at column 0 ends an active block scalar rather than
|
||||
// being its content. Close the scalar's indentation here, dedenting back to the document
|
||||
// level, so the marker is then scanned balanced at the document level. Without this the
|
||||
// scalar's indent lingers past the marker and surfaces later as a stray dedent plus a
|
||||
// phantom empty node (the marker still ends the document, but the structure is unbalanced).
|
||||
if state.blockScalarIndentation != nil, width == 0, isAtDocumentMarker(state.reader) {
|
||||
state.blockScalarIndentation = nil
|
||||
state.blockScalarContentPrefix = ""
|
||||
while state.indentation.count > 1 {
|
||||
state.indentation.removeLast()
|
||||
state.append(.dedent(width: state.indentation.last ?? 0), mark: end, endMark: end)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if consumeBlockScalarContentIndentation(width: width, state: &state) {
|
||||
return
|
||||
}
|
||||
|
||||
27
Tests/BlockScalarDocumentBoundaryTests.swift
Normal file
27
Tests/BlockScalarDocumentBoundaryTests.swift
Normal file
@ -0,0 +1,27 @@
|
||||
@testable import PureYAML
|
||||
import Testing
|
||||
|
||||
/// A root block scalar whose content runs to column 0 is ended by a document marker (`...` or
|
||||
/// `---`), not continued into it. The scalar's indentation is closed at the marker, so the stream
|
||||
/// stays balanced: no stray dedent and no phantom empty document afterward.
|
||||
@Suite("Block scalar ended by document boundary")
|
||||
struct BlockScalarDocumentBoundaryTests {
|
||||
@Test("A `...` ends a root block scalar, yielding a single document")
|
||||
func test_terminatedByDocumentEnd() throws {
|
||||
let documents = try PureYAML.parseStream("--- |\n%!PS\n...\n").map(\.value)
|
||||
#expect(documents == [.string("%!PS\n")])
|
||||
}
|
||||
|
||||
@Test("A `---` ends a root block scalar and starts the next document")
|
||||
func test_terminatedByNextDocumentStart() throws {
|
||||
let documents = try PureYAML.parseStream("--- |\n%!PS\n--- next\n").map(\.value)
|
||||
#expect(documents == [.string("%!PS\n"), .string("next")])
|
||||
}
|
||||
|
||||
@Test("Suite case W4TN: a directive, a root literal block scalar, then a comment-only document")
|
||||
func test_w4tnShape() throws {
|
||||
let yaml = "%YAML 1.2\n--- |\n%!PS-Adobe-2.0\n...\n%YAML 1.2\n---\n# Empty\n...\n"
|
||||
let documents = try PureYAML.parseStream(yaml).map(\.value)
|
||||
#expect(documents == [.string("%!PS-Adobe-2.0\n"), .null])
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user