fix(parsing): reject a later under-indented property on a mapping value
The value-property indentation check used only the first property's mark,
so it caught a sole under-indented property ('seq:' then '&anchor') but not
a second one after an inline first ('key: &x' then a '!!tag' in column 1),
which still parsed.
The last consumed property is cursor.previous after consumeProperties, so
the check now uses it instead of the first mark, catching an under-indented
property whether it is the only one or a later one. Inline properties, a
property indented under the key, and a properly indented anchor-and-tag pair
are unaffected.
Measured against the official YAML test-suite, parse-level conformance
rises from 277/333 (83.2%) to 278/333 (83.5%) with no regression.
This commit is contained in:
parent
d79df8c4bc
commit
25b1388dbb
@ -30,10 +30,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
flow collection on its own line, and nested flow collections are unaffected. Lifts official
|
||||
test-suite parse-level conformance from 276/333 (82.9%) to 277/333 (83.2%), with no regression.
|
||||
- A mapping value's anchor or tag on the line below the key must now be indented past the key. A
|
||||
property at the key's own indentation (`seq:` then `&anchor` in column 1) is ambiguous with a
|
||||
sibling and is rejected, while an inline property, a property indented under the key, and a block
|
||||
sequence at the key's indent (which carries no property) stay valid. Lifts official test-suite
|
||||
parse-level conformance from 275/333 (82.6%) to 276/333 (82.9%), with no regression.
|
||||
property at the key's own indentation is ambiguous with a sibling and is rejected, whether it is
|
||||
the only property (`seq:` then `&anchor` in column 1) or a later one after an inline first
|
||||
(`key: &x` then a `!!tag` in column 1). An inline property, a property indented under the key, and
|
||||
a block sequence at the key's indent (which carries no property) stay valid. Lifts official
|
||||
test-suite parse-level conformance from 275/333 (82.6%) to 278/333 (83.5%), with no regression.
|
||||
- A `-` immediately before a flow indicator is no longer treated as a scalar. In a flow collection
|
||||
a `-` that begins a plain scalar must be followed by a non-indicator character, so `[-]`,
|
||||
`[-, -]`, and `{a: -}` are now rejected. A dash followed by ordinary content is unaffected:
|
||||
|
||||
@ -66,20 +66,22 @@ extension PureYAML.Parsing.TokenEventParser {
|
||||
return result
|
||||
}
|
||||
|
||||
/// A value's anchor or tag on a line below the `:` must be indented past the key. Reaching the
|
||||
/// value-property consumption with a property on a later line means no indent token preceded it
|
||||
/// (a properly indented one is consumed inside the indented value), so it sits at the key's
|
||||
/// level and is malformed (`seq:` then `&anchor` in column 1).
|
||||
/// A value's anchor or tag on a line below the `:` must be indented past the key. A properly
|
||||
/// indented property is preceded by an indent token and consumed inside the indented value, so a
|
||||
/// property consumed here on a line below the `:` sits at the key's level and is malformed. The
|
||||
/// last consumed property is `cursor.previous`; checking it catches both a single under-indented
|
||||
/// property (`seq:` then `&anchor`) and a second one after an inline first (`key: &x` then a
|
||||
/// `!!tag` in column 1).
|
||||
func enforceValuePropertyIndented(
|
||||
_ properties: PureYAML.Parsing.NodeProperties,
|
||||
valueIndicator: PureYAML.Parsing.Token,
|
||||
) throws {
|
||||
guard properties != .none, let propertyMark = properties.mark,
|
||||
propertyMark.line != valueIndicator.mark.line
|
||||
guard properties != .none, let lastProperty = cursor.previous,
|
||||
lastProperty.mark.line != valueIndicator.mark.line
|
||||
else {
|
||||
return
|
||||
}
|
||||
throw PureYAML.Parsing.ParseError.unexpectedIndentation(line: propertyMark.line)
|
||||
throw PureYAML.Parsing.ParseError.unexpectedIndentation(line: lastProperty.mark.line)
|
||||
}
|
||||
|
||||
/// Emit an empty (null) scalar as a mapping value and return its node result, used where a
|
||||
|
||||
@ -3,16 +3,21 @@ import Testing
|
||||
|
||||
@Suite("A mapping value's property indentation")
|
||||
struct ValuePropertyIndentationTests {
|
||||
@Test("A value's anchor on a line below the key, at the key's indent, is rejected")
|
||||
func test_underIndentedValuePropertyRejected() throws {
|
||||
@Test("An under-indented value property is rejected, whether it is the first or a later one", arguments: [
|
||||
"---\nseq:\n&anchor\n- a\n- b\n", // a sole anchor at the key's indent
|
||||
"key: &x\n!!map\n a: b\n", // a second property (a tag) at the key's indent
|
||||
])
|
||||
func test_underIndentedValuePropertyRejected(_ yaml: String) throws {
|
||||
#expect(throws: PureYAML.Parsing.ParseError.self) {
|
||||
try PureYAML.parse("---\nseq:\n&anchor\n- a\n- b\n")
|
||||
try PureYAML.parse(yaml)
|
||||
}
|
||||
}
|
||||
|
||||
@Test("Properties indented past the key, or inline, stay valid", arguments: [
|
||||
"seq:\n &a\n - x\n", // an anchor indented under the key
|
||||
"key: &a value\n", // an inline anchor on the value
|
||||
"key: &a !!str value\n", // an inline anchor and tag
|
||||
"key:\n &a !!map\n a: b\n", // properly indented anchor and tag
|
||||
"seq:\n- a\n- b\n", // a block sequence at the key's indent (no property)
|
||||
"key:\n &a sub: v\n", // an indented anchored key
|
||||
])
|
||||
|
||||
Loading…
Reference in New Issue
Block a user