fix(parsing): keep a leading percent in a block scalar literal
A zero-indent literal or folded block scalar sits at column 0, where the directive scan runs, so a content line beginning with `%` (`%!PS-Adobe-2.0`) was misread as a directive and rejected as unsupported. The directive scan now runs only outside a block scalar, so a leading `%` in block scalar content is literal text. A real `%YAML` or `%TAG` directive still parses, and a stray `%` in other content is still rejected rather than silently accepted, so the should-error behaviour is unchanged. This is groundwork for yaml-test-suite W4TN, which additionally needs a block scalar to be terminated by `...` and per-document directives across a multi- document stream, so conformance counts are unchanged this step.
This commit is contained in:
parent
5ea6fa668b
commit
942a7ff2bc
@ -84,6 +84,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Fixed
|
||||
|
||||
- A line beginning with `%` inside a block scalar is now kept as literal content rather than being
|
||||
misread as a directive. A zero-indent literal or folded scalar sits at column 0, where the
|
||||
directive scan runs, so a content line such as `%!PS-Adobe-2.0` was rejected as an unsupported
|
||||
directive. The directive scan now runs only outside a block scalar; a real `%YAML`/`%TAG`
|
||||
directive and the rejection of a stray `%` in other content are unchanged. This is groundwork for
|
||||
yaml-test-suite W4TN, which additionally needs block-scalar termination by `...` and per-document
|
||||
directives, so conformance counts are unchanged.
|
||||
|
||||
- A block sequence value carrying an inline property (`sequence: !!seq` then `- entry` at the key's
|
||||
column) is now correctly terminated by a sibling mapping key. Such a zero-indent sequence has its
|
||||
entries at the mapping key's own indentation, so a following key ends it. The untagged form already
|
||||
|
||||
@ -3,7 +3,11 @@ extension PureYAML.Parsing.Scanner {
|
||||
guard state.indentation.last == 0 else {
|
||||
return false
|
||||
}
|
||||
if state.reader.peek() == "%" {
|
||||
// A `%` opens a directive only outside a block scalar. Inside one (a zero-indent literal or
|
||||
// folded scalar sits at column 0, where this directive check runs) a leading `%` is literal
|
||||
// content, so let the main scanner read the line. Elsewhere the directive path still runs, so
|
||||
// a stray `%` in other content is rejected as before, not silently accepted.
|
||||
if state.reader.peek() == "%", state.blockScalarIndentation == nil {
|
||||
try scanDirective(&state)
|
||||
return true
|
||||
}
|
||||
|
||||
30
Tests/BlockScalarPercentContentTests.swift
Normal file
30
Tests/BlockScalarPercentContentTests.swift
Normal file
@ -0,0 +1,30 @@
|
||||
@testable import PureYAML
|
||||
import Testing
|
||||
|
||||
@Suite("A percent inside a block scalar is literal content, not a directive")
|
||||
struct BlockScalarPercentContentTests {
|
||||
/// A zero-indent block scalar sits at column 0, where the directive scan runs, so a content line
|
||||
/// beginning with `%` was misread as a directive and rejected. Inside a block scalar a leading
|
||||
/// `%` is literal text (groundwork for yaml-test-suite W4TN, which also needs block-scalar
|
||||
/// termination by `...` and multi-document directives).
|
||||
@Test("A root literal block scalar keeps a leading percent as content")
|
||||
func test_rootBlockScalarPercentContent() throws {
|
||||
#expect(try PureYAML.parse("--- |\n%foo\n") == .string("%foo\n"))
|
||||
}
|
||||
|
||||
/// Every content line of the block scalar keeps its leading percent, not only the first.
|
||||
@Test("Each block scalar line keeps its leading percent")
|
||||
func test_multilineBlockScalarPercentContent() throws {
|
||||
#expect(try PureYAML.parse("--- |\n%one\n%two\n") == .string("%one\n%two\n"))
|
||||
}
|
||||
|
||||
/// The change is scoped to block scalars: a real `%YAML` directive still works, and a stray `%`
|
||||
/// in other content is still rejected rather than silently accepted.
|
||||
@Test("A directive still parses and a stray percent in content still errors")
|
||||
func test_directiveStillWorksAndStrayPercentRejected() throws {
|
||||
#expect(try PureYAML.parse("%YAML 1.2\n---\nx\n") == .string("x"))
|
||||
#expect(throws: PureYAML.Parsing.ParseError.self) {
|
||||
try PureYAML.parse("{ a,\n%x }\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user