diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ba67c7..9d38cab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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: diff --git a/Sources/Parsing/TokenEventParser.Helpers.swift b/Sources/Parsing/TokenEventParser.Helpers.swift index 1e75203..3a18b66 100644 --- a/Sources/Parsing/TokenEventParser.Helpers.swift +++ b/Sources/Parsing/TokenEventParser.Helpers.swift @@ -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 diff --git a/Tests/ValuePropertyIndentationTests.swift b/Tests/ValuePropertyIndentationTests.swift index a4d7cad..71a2139 100644 --- a/Tests/ValuePropertyIndentationTests.swift +++ b/Tests/ValuePropertyIndentationTests.swift @@ -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 ])