Rules: indentation: Handle imbricated flows correctly

The following source -- although not loadable by pyyaml -- is valid
YAML:

    {{key}}: value

This was processed badly by yamllint. The same for `[[value]]`,
`{{{{{moustaches}}}}}` or:

    {[val,
      {{key: val,
        key2}}]}

This patch corrects it and add corresponding test cases.

Related-to: #3
pull/4/head
Adrien Vergé 9 years ago
parent f98bed1085
commit 76f47e91ca

@ -381,6 +381,141 @@ class IndentationStackTestCase(RuleTestCase):
# missing BEnd here # missing BEnd here
' BEnd \n') ' BEnd \n')
def test_flows_imbrication(self):
self.assertMultiLineEqual(
self.full_stack('[[val]]\n'),
'FSeqStart F_SEQ:1\n'
'FSeqStart F_SEQ:1 F_SEQ:2\n'
' Scalar F_SEQ:1 F_SEQ:2\n'
' FSeqEnd F_SEQ:1\n'
' FSeqEnd \n')
self.assertMultiLineEqual(
self.full_stack('[[val], [val2]]\n'),
'FSeqStart F_SEQ:1\n'
'FSeqStart F_SEQ:1 F_SEQ:2\n'
' Scalar F_SEQ:1 F_SEQ:2\n'
' FSeqEnd F_SEQ:1\n'
' FEntry F_SEQ:1\n'
'FSeqStart F_SEQ:1 F_SEQ:9\n'
' Scalar F_SEQ:1 F_SEQ:9\n'
' FSeqEnd F_SEQ:1\n'
' FSeqEnd \n')
self.assertMultiLineEqual(
self.full_stack('{{key}}\n'),
'FMapStart F_MAP:1\n'
'FMapStart F_MAP:1 F_MAP:2\n'
' Scalar F_MAP:1 F_MAP:2\n'
' FMapEnd F_MAP:1\n'
' FMapEnd \n')
self.assertMultiLineEqual(
self.full_stack('[key]: value\n'),
'BMapStart B_MAP:0\n'
' Key B_MAP:0 KEY:0\n'
'FSeqStart B_MAP:0 KEY:0 F_SEQ:1\n'
' Scalar B_MAP:0 KEY:0 F_SEQ:1\n'
' FSeqEnd B_MAP:0 KEY:0\n'
' Value B_MAP:0 KEY:0 VAL:7\n'
' Scalar B_MAP:0\n'
' BEnd \n')
self.assertMultiLineEqual(
self.full_stack('[[key]]: value\n'),
'BMapStart B_MAP:0\n'
' Key B_MAP:0 KEY:0\n'
'FSeqStart B_MAP:0 KEY:0 F_SEQ:1\n'
'FSeqStart B_MAP:0 KEY:0 F_SEQ:1 F_SEQ:2\n'
' Scalar B_MAP:0 KEY:0 F_SEQ:1 F_SEQ:2\n'
' FSeqEnd B_MAP:0 KEY:0 F_SEQ:1\n'
' FSeqEnd B_MAP:0 KEY:0\n'
' Value B_MAP:0 KEY:0 VAL:9\n'
' Scalar B_MAP:0\n'
' BEnd \n')
self.assertMultiLineEqual(
self.full_stack('{key}: value\n'),
'BMapStart B_MAP:0\n'
' Key B_MAP:0 KEY:0\n'
'FMapStart B_MAP:0 KEY:0 F_MAP:1\n'
' Scalar B_MAP:0 KEY:0 F_MAP:1\n'
' FMapEnd B_MAP:0 KEY:0\n'
' Value B_MAP:0 KEY:0 VAL:7\n'
' Scalar B_MAP:0\n'
' BEnd \n')
self.assertMultiLineEqual(
self.full_stack('{key: value}: value\n'),
'BMapStart B_MAP:0\n'
' Key B_MAP:0 KEY:0\n'
'FMapStart B_MAP:0 KEY:0 F_MAP:1\n'
' Key B_MAP:0 KEY:0 F_MAP:1 KEY:1\n'
' Scalar B_MAP:0 KEY:0 F_MAP:1 KEY:1\n'
' Value B_MAP:0 KEY:0 F_MAP:1 KEY:1 VAL:6\n'
' Scalar B_MAP:0 KEY:0 F_MAP:1\n'
' FMapEnd B_MAP:0 KEY:0\n'
' Value B_MAP:0 KEY:0 VAL:14\n'
' Scalar B_MAP:0\n'
' BEnd \n')
self.assertMultiLineEqual(
self.full_stack('{{key}}: value\n'),
'BMapStart B_MAP:0\n'
' Key B_MAP:0 KEY:0\n'
'FMapStart B_MAP:0 KEY:0 F_MAP:1\n'
'FMapStart B_MAP:0 KEY:0 F_MAP:1 F_MAP:2\n'
' Scalar B_MAP:0 KEY:0 F_MAP:1 F_MAP:2\n'
' FMapEnd B_MAP:0 KEY:0 F_MAP:1\n'
' FMapEnd B_MAP:0 KEY:0\n'
' Value B_MAP:0 KEY:0 VAL:9\n'
' Scalar B_MAP:0\n'
' BEnd \n')
self.assertMultiLineEqual(
self.full_stack('{{key}: val, {key2}: {val2}}\n'),
'FMapStart F_MAP:1\n'
' Key F_MAP:1 KEY:1\n'
'FMapStart F_MAP:1 KEY:1 F_MAP:2\n'
' Scalar F_MAP:1 KEY:1 F_MAP:2\n'
' FMapEnd F_MAP:1 KEY:1\n'
' Value F_MAP:1 KEY:1 VAL:8\n'
' Scalar F_MAP:1\n'
' FEntry F_MAP:1\n'
' Key F_MAP:1 KEY:1\n'
'FMapStart F_MAP:1 KEY:1 F_MAP:14\n'
' Scalar F_MAP:1 KEY:1 F_MAP:14\n'
' FMapEnd F_MAP:1 KEY:1\n'
' Value F_MAP:1 KEY:1 VAL:21\n'
'FMapStart F_MAP:1 KEY:1 VAL:21 F_MAP:22\n'
' Scalar F_MAP:1 KEY:1 VAL:21 F_MAP:22\n'
' FMapEnd F_MAP:1\n'
' FMapEnd \n')
self.assertMultiLineEqual(
self.full_stack('{[{{[val]}}, [{[key]: val2}]]}\n'),
'FMapStart F_MAP:1\n'
'FSeqStart F_MAP:1 F_SEQ:2\n'
'FMapStart F_MAP:1 F_SEQ:2 F_MAP:3\n'
'FMapStart F_MAP:1 F_SEQ:2 F_MAP:3 F_MAP:4\n'
'FSeqStart F_MAP:1 F_SEQ:2 F_MAP:3 F_MAP:4 F_SEQ:5\n'
' Scalar F_MAP:1 F_SEQ:2 F_MAP:3 F_MAP:4 F_SEQ:5\n'
' FSeqEnd F_MAP:1 F_SEQ:2 F_MAP:3 F_MAP:4\n'
' FMapEnd F_MAP:1 F_SEQ:2 F_MAP:3\n'
' FMapEnd F_MAP:1 F_SEQ:2\n'
' FEntry F_MAP:1 F_SEQ:2\n'
'FSeqStart F_MAP:1 F_SEQ:2 F_SEQ:14\n'
'FMapStart F_MAP:1 F_SEQ:2 F_SEQ:14 F_MAP:15\n'
' Key F_MAP:1 F_SEQ:2 F_SEQ:14 F_MAP:15 KEY:15\n'
'FSeqStart F_MAP:1 F_SEQ:2 F_SEQ:14 F_MAP:15 KEY:15 F_SEQ:16\n'
' Scalar F_MAP:1 F_SEQ:2 F_SEQ:14 F_MAP:15 KEY:15 F_SEQ:16\n'
' FSeqEnd F_MAP:1 F_SEQ:2 F_SEQ:14 F_MAP:15 KEY:15\n'
' Value F_MAP:1 F_SEQ:2 F_SEQ:14 F_MAP:15 KEY:15 VAL:22\n'
' Scalar F_MAP:1 F_SEQ:2 F_SEQ:14 F_MAP:15\n'
' FMapEnd F_MAP:1 F_SEQ:2 F_SEQ:14\n'
' FSeqEnd F_MAP:1 F_SEQ:2\n'
' FSeqEnd F_MAP:1\n'
' FMapEnd \n')
class IndentationTestCase(RuleTestCase): class IndentationTestCase(RuleTestCase):
rule_id = 'indentation' rule_id = 'indentation'
@ -1288,6 +1423,48 @@ class IndentationTestCase(RuleTestCase):
'- Clark Evans\n' '- Clark Evans\n'
'- Ingy döt Net\n', conf) '- Ingy döt Net\n', conf)
def test_flows_imbrication(self):
conf = 'indentation: {spaces: consistent}'
self.check('---\n'
'[val]: value\n', conf)
self.check('---\n'
'{key}: value\n', conf)
self.check('---\n'
'{key: val}: value\n', conf)
self.check('---\n'
'[[val]]: value\n', conf)
self.check('---\n'
'{{key}}: value\n', conf)
self.check('---\n'
'{{key: val1}: val2}: value\n', conf)
self.check('---\n'
'- [val, {{key: val}: val}]: value\n'
'- {[val,\n'
' {{key: val}: val}]}\n'
'- {[val,\n'
' {{key: val,\n'
' key2}}]}\n'
'- {{{{{moustaches}}}}}\n'
'- {{{{{moustache,\n'
' moustache},\n'
' moustache}},\n'
' moustache}}\n', conf)
self.check('---\n'
'- {[val,\n'
' {{key: val}: val}]}\n',
conf, problem=(3, 6))
self.check('---\n'
'- {[val,\n'
' {{key: val,\n'
' key2}}]}\n',
conf, problem=(4, 6))
self.check('---\n'
'- {{{{{moustache,\n'
' moustache},\n'
' moustache}},\n'
' moustache}}\n',
conf, problem1=(4, 8), problem2=(5, 4))
class ScalarIndentationTestCase(RuleTestCase): class ScalarIndentationTestCase(RuleTestCase):
rule_id = 'indentation' rule_id = 'indentation'

@ -497,12 +497,16 @@ def _check(conf, token, prev, next, nextnext, context):
consumed_current_token = False consumed_current_token = False
while True: while True:
if (context['stack'][-1].type == F_SEQ and if (context['stack'][-1].type == F_SEQ and
isinstance(token, yaml.FlowSequenceEndToken)): isinstance(token, yaml.FlowSequenceEndToken) and
not consumed_current_token):
context['stack'].pop() context['stack'].pop()
consumed_current_token = True
elif (context['stack'][-1].type == F_MAP and elif (context['stack'][-1].type == F_MAP and
isinstance(token, yaml.FlowMappingEndToken)): isinstance(token, yaml.FlowMappingEndToken) and
not consumed_current_token):
context['stack'].pop() context['stack'].pop()
consumed_current_token = True
elif (context['stack'][-1].type in (B_MAP, B_SEQ) and elif (context['stack'][-1].type in (B_MAP, B_SEQ) and
isinstance(token, yaml.BlockEndToken) and isinstance(token, yaml.BlockEndToken) and

Loading…
Cancel
Save