diff --git a/tests/rules/test_indentation.py b/tests/rules/test_indentation.py index e9f2069..a8f91fd 100644 --- a/tests/rules/test_indentation.py +++ b/tests/rules/test_indentation.py @@ -217,6 +217,89 @@ class IndentationStackTestCase(RuleTestCase): ' FSeqEnd B_MAP:0\n' ' BEnd \n') + def test_anchors(self): + self.assertMultiLineEqual( + self.full_stack('key: &anchor value\n'), + 'BMapStart B_MAP:0\n' + ' Key B_MAP:0 KEY:0\n' + ' Scalar B_MAP:0 KEY:0\n' + ' Value B_MAP:0 KEY:0 VAL:5\n' + ' Anchor B_MAP:0 KEY:0 VAL:5\n' + ' Scalar B_MAP:0\n' + ' BEnd \n') + + self.assertMultiLineEqual( + self.full_stack('key: &anchor\n' + ' value\n'), + 'BMapStart B_MAP:0\n' + ' Key B_MAP:0 KEY:0\n' + ' Scalar B_MAP:0 KEY:0\n' + ' Value B_MAP:0 KEY:0 VAL:2\n' + ' Anchor B_MAP:0 KEY:0 VAL:2\n' + ' Scalar B_MAP:0\n' + ' BEnd \n') + + self.assertMultiLineEqual( + self.full_stack('- &anchor value\n'), + 'BSeqStart B_SEQ:0\n' + ' BEntry B_SEQ:0 B_ENT:2\n' + ' Anchor B_SEQ:0 B_ENT:2\n' + ' Scalar B_SEQ:0\n' + ' BEnd \n') + + self.assertMultiLineEqual( + self.full_stack('- &anchor\n' + ' value\n'), + 'BSeqStart B_SEQ:0\n' + ' BEntry B_SEQ:0 B_ENT:2\n' + ' Anchor B_SEQ:0 B_ENT:2\n' + ' Scalar B_SEQ:0\n' + ' BEnd \n') + + self.assertMultiLineEqual( + self.full_stack('- &anchor\n' + ' - 1\n' + ' - 2\n'), + 'BSeqStart B_SEQ:0\n' + ' BEntry B_SEQ:0 B_ENT:2\n' + ' Anchor B_SEQ:0 B_ENT:2\n' + 'BSeqStart B_SEQ:0 B_ENT:2 B_SEQ:2\n' + ' BEntry B_SEQ:0 B_ENT:2 B_SEQ:2 B_ENT:4\n' + ' Scalar B_SEQ:0 B_ENT:2 B_SEQ:2\n' + ' BEntry B_SEQ:0 B_ENT:2 B_SEQ:2 B_ENT:4\n' + ' Scalar B_SEQ:0 B_ENT:2 B_SEQ:2\n' + ' BEnd B_SEQ:0\n' + ' BEnd \n') + + self.assertMultiLineEqual( + self.full_stack('&anchor key:\n' + ' value\n'), + 'BMapStart B_MAP:0\n' + ' Key B_MAP:0 KEY:0\n' + ' Anchor B_MAP:0 KEY:0\n' + ' Scalar B_MAP:0 KEY:0\n' + ' Value B_MAP:0 KEY:0 VAL:2\n' + ' Scalar B_MAP:0\n' + ' BEnd \n') + + self.assertMultiLineEqual( + self.full_stack('pre:\n' + ' &anchor1 0\n' + '&anchor2 key:\n' + ' value\n'), + 'BMapStart B_MAP:0\n' + ' Key B_MAP:0 KEY:0\n' + ' Scalar B_MAP:0 KEY:0\n' + ' Value B_MAP:0 KEY:0 VAL:2\n' + ' Anchor B_MAP:0 KEY:0 VAL:2\n' + ' Scalar B_MAP:0\n' + ' Key B_MAP:0 KEY:0\n' + ' Anchor B_MAP:0 KEY:0\n' + ' Scalar B_MAP:0 KEY:0\n' + ' Value B_MAP:0 KEY:0 VAL:2\n' + ' Scalar B_MAP:0\n' + ' BEnd \n') + class IndentationTestCase(RuleTestCase): rule_id = 'indentation' @@ -871,6 +954,66 @@ class IndentationTestCase(RuleTestCase): ' line\n' '...\n', conf, problem=(4, 6)) + def test_anchors(self): + conf = 'indentation: {spaces: 2}' + self.check('---\n' + 'key: &anchor value\n', conf) + self.check('---\n' + 'key: &anchor\n' + ' value\n', conf) + self.check('---\n' + '- &anchor value\n', conf) + self.check('---\n' + '- &anchor\n' + ' value\n', conf) + self.check('---\n' + 'key: &anchor [1,\n' + ' 2]\n', conf) + self.check('---\n' + 'key: &anchor\n' + ' [1,\n' + ' 2]\n', conf) + self.check('---\n' + 'key: &anchor\n' + ' - 1\n' + ' - 2\n', conf) + self.check('---\n' + '- &anchor [1,\n' + ' 2]\n', conf) + self.check('---\n' + '- &anchor\n' + ' [1,\n' + ' 2]\n', conf) + self.check('---\n' + '- &anchor\n' + ' - 1\n' + ' - 2\n', conf) + self.check('---\n' + 'key:\n' + ' &anchor1\n' + ' value\n', conf) + self.check('---\n' + 'pre:\n' + ' &anchor1 0\n' + '&anchor2 key:\n' + ' value\n', conf) + self.check('---\n' + 'machine0:\n' + ' /etc/hosts: &ref-etc-hosts\n' + ' content:\n' + ' - 127.0.0.1: localhost\n' + ' - ::1: localhost\n' + ' mode: 0644\n' + 'machine1:\n' + ' /etc/hosts: *ref-etc-hosts\n', conf) + self.check('---\n' + 'list:\n' + ' - k: v\n' + ' - &a truc\n' + ' - &b\n' + ' truc\n' + ' - k: *a\n', conf) + class ScalarIndentationTestCase(RuleTestCase): rule_id = 'indentation' diff --git a/yamllint/rules/indentation.py b/yamllint/rules/indentation.py index e889594..68e8157 100644 --- a/yamllint/rules/indentation.py +++ b/yamllint/rules/indentation.py @@ -367,6 +367,14 @@ def check(conf, token, prev, next, nextnext, context): elif isinstance(token, yaml.ValueToken): assert context['stack'][-1].type == KEY + # Special case: + # key: &anchor + # value + if isinstance(next, yaml.AnchorToken): + if (next.start_mark.line == prev.start_mark.line and + next.start_mark.line < nextnext.start_mark.line): + next = nextnext + # Only if value is not empty if not isinstance(next, (yaml.BlockEndToken, yaml.FlowMappingEndToken, @@ -442,10 +450,11 @@ def check(conf, token, prev, next, nextnext, context): context['stack'].pop() elif (context['stack'][-1].type == VAL and - not isinstance(token, yaml.ValueToken)): - assert context['stack'][-2].type == KEY - context['stack'].pop() - context['stack'].pop() + not isinstance(token, yaml.ValueToken) and + not isinstance(token, yaml.AnchorToken)): + assert context['stack'][-2].type == KEY + context['stack'].pop() + context['stack'].pop() elif (context['stack'][-1].type == KEY and isinstance(next, (yaml.BlockEndToken,