mirror of
https://github.com/adrienverge/yamllint.git
synced 2025-02-25 18:55:20 -06:00
Rules: indentation: Check multi-line scalars
This commit is contained in:
parent
96465008ab
commit
67d13d60ae
@ -488,3 +488,234 @@ class IndentationTestCase(RuleTestCase):
|
|||||||
' :\n'
|
' :\n'
|
||||||
' value\n'
|
' value\n'
|
||||||
'...\n', conf, problem1=(4, 10), problem2=(6, 8))
|
'...\n', conf, problem1=(4, 10), problem2=(6, 8))
|
||||||
|
|
||||||
|
|
||||||
|
class ScalarIndentationTestCase(RuleTestCase):
|
||||||
|
rule_id = 'indentation'
|
||||||
|
|
||||||
|
def test_basics_plain(self):
|
||||||
|
conf = ('indentation: {spaces: 2}\n'
|
||||||
|
'document-start: disable\n')
|
||||||
|
self.check('multi\n'
|
||||||
|
'line\n', conf)
|
||||||
|
self.check('multi\n'
|
||||||
|
' line\n', conf, problem=(2, 2))
|
||||||
|
self.check('- multi\n'
|
||||||
|
' line\n', conf)
|
||||||
|
self.check('- multi\n'
|
||||||
|
' line\n', conf, problem=(2, 4))
|
||||||
|
self.check('a key: multi\n'
|
||||||
|
' line\n', conf)
|
||||||
|
self.check('a key: multi\n'
|
||||||
|
' line\n', conf, problem=(2, 9))
|
||||||
|
self.check('a key:\n'
|
||||||
|
' multi\n'
|
||||||
|
' line\n', conf)
|
||||||
|
self.check('a key:\n'
|
||||||
|
' multi\n'
|
||||||
|
' line\n', conf, problem=(3, 4))
|
||||||
|
|
||||||
|
def test_basics_quoted(self):
|
||||||
|
conf = ('indentation: {spaces: 2}\n'
|
||||||
|
'document-start: disable\n')
|
||||||
|
self.check('"multi\n'
|
||||||
|
' line"\n', conf)
|
||||||
|
self.check('"multi\n'
|
||||||
|
'line"\n', conf, problem=(2, 1))
|
||||||
|
self.check('"multi\n'
|
||||||
|
' line"\n', conf, problem=(2, 3))
|
||||||
|
self.check('- "multi\n'
|
||||||
|
' line"\n', conf)
|
||||||
|
self.check('- "multi\n'
|
||||||
|
' line"\n', conf, problem=(2, 3))
|
||||||
|
self.check('- "multi\n'
|
||||||
|
' line"\n', conf, problem=(2, 5))
|
||||||
|
self.check('a key: "multi\n'
|
||||||
|
' line"\n', conf)
|
||||||
|
self.check('a key: "multi\n'
|
||||||
|
' line"\n', conf, problem=(2, 8))
|
||||||
|
self.check('a key: "multi\n'
|
||||||
|
' line"\n', conf, problem=(2, 10))
|
||||||
|
self.check('a key:\n'
|
||||||
|
' "multi\n'
|
||||||
|
' line"\n', conf)
|
||||||
|
self.check('a key:\n'
|
||||||
|
' "multi\n'
|
||||||
|
' line"\n', conf, problem=(3, 3))
|
||||||
|
self.check('a key:\n'
|
||||||
|
' "multi\n'
|
||||||
|
' line"\n', conf, problem=(3, 5))
|
||||||
|
|
||||||
|
def test_basics_folded_style(self):
|
||||||
|
conf = ('indentation: {spaces: 2}\n'
|
||||||
|
'document-start: disable\n')
|
||||||
|
self.check('>\n'
|
||||||
|
' multi\n'
|
||||||
|
' line\n', conf)
|
||||||
|
self.check('- >\n'
|
||||||
|
' multi\n'
|
||||||
|
' line\n', conf)
|
||||||
|
self.check('- key: >\n'
|
||||||
|
' multi\n'
|
||||||
|
' line\n', conf)
|
||||||
|
self.check('- key:\n'
|
||||||
|
' >\n'
|
||||||
|
' multi\n'
|
||||||
|
' line\n', conf)
|
||||||
|
self.check('- ? >\n'
|
||||||
|
' multi-line\n'
|
||||||
|
' key\n'
|
||||||
|
' : >\n'
|
||||||
|
' multi-line\n'
|
||||||
|
' value\n', conf)
|
||||||
|
self.check('- ?\n'
|
||||||
|
' >\n'
|
||||||
|
' multi-line\n'
|
||||||
|
' key\n'
|
||||||
|
' :\n'
|
||||||
|
' >\n'
|
||||||
|
' multi-line\n'
|
||||||
|
' value\n', conf)
|
||||||
|
|
||||||
|
def test_basics_literal_style(self):
|
||||||
|
conf = ('indentation: {spaces: 2}\n'
|
||||||
|
'document-start: disable\n')
|
||||||
|
self.check('|\n'
|
||||||
|
' multi\n'
|
||||||
|
' line\n', conf)
|
||||||
|
self.check('- |\n'
|
||||||
|
' multi\n'
|
||||||
|
' line\n', conf)
|
||||||
|
self.check('- key: |\n'
|
||||||
|
' multi\n'
|
||||||
|
' line\n', conf)
|
||||||
|
self.check('- key:\n'
|
||||||
|
' |\n'
|
||||||
|
' multi\n'
|
||||||
|
' line\n', conf)
|
||||||
|
self.check('- ? |\n'
|
||||||
|
' multi-line\n'
|
||||||
|
' key\n'
|
||||||
|
' : |\n'
|
||||||
|
' multi-line\n'
|
||||||
|
' value\n', conf)
|
||||||
|
self.check('- ?\n'
|
||||||
|
' |\n'
|
||||||
|
' multi-line\n'
|
||||||
|
' key\n'
|
||||||
|
' :\n'
|
||||||
|
' |\n'
|
||||||
|
' multi-line\n'
|
||||||
|
' value\n', conf)
|
||||||
|
|
||||||
|
# The following "paragraph" examples are inspired from
|
||||||
|
# http://stackoverflow.com/questions/3790454/in-yaml-how-do-i-break-a-string-over-multiple-lines
|
||||||
|
|
||||||
|
def test_paragraph_plain(self):
|
||||||
|
conf = ('indentation: {spaces: 2}\n'
|
||||||
|
'document-start: disable\n')
|
||||||
|
self.check('- long text: very "long"\n'
|
||||||
|
' \'string\' with\n'
|
||||||
|
'\n'
|
||||||
|
' paragraph gap, \\n and\n'
|
||||||
|
' spaces.\n', conf)
|
||||||
|
self.check('- long text: very "long"\n'
|
||||||
|
' \'string\' with\n'
|
||||||
|
'\n'
|
||||||
|
' paragraph gap, \\n and\n'
|
||||||
|
' spaces.\n', conf,
|
||||||
|
problem1=(2, 5), problem2=(4, 5), problem3=(5, 5))
|
||||||
|
self.check('- long text:\n'
|
||||||
|
' very "long"\n'
|
||||||
|
' \'string\' with\n'
|
||||||
|
'\n'
|
||||||
|
' paragraph gap, \\n and\n'
|
||||||
|
' spaces.\n', conf)
|
||||||
|
|
||||||
|
def test_paragraph_double_quoted(self):
|
||||||
|
conf = ('indentation: {spaces: 2}\n'
|
||||||
|
'document-start: disable\n')
|
||||||
|
self.check('- long text: "very \\"long\\"\n'
|
||||||
|
' \'string\' with\n'
|
||||||
|
'\n'
|
||||||
|
' paragraph gap, \\n and\n'
|
||||||
|
' spaces."\n', conf)
|
||||||
|
self.check('- long text: "very \\"long\\"\n'
|
||||||
|
' \'string\' with\n'
|
||||||
|
'\n'
|
||||||
|
' paragraph gap, \\n and\n'
|
||||||
|
' spaces."\n', conf,
|
||||||
|
problem1=(2, 5), problem2=(4, 5), problem3=(5, 5))
|
||||||
|
self.check('- long text: "very \\"long\\"\n'
|
||||||
|
'\'string\' with\n'
|
||||||
|
'\n'
|
||||||
|
'paragraph gap, \\n and\n'
|
||||||
|
'spaces."\n', conf,
|
||||||
|
problem1=(2, 1), problem2=(4, 1), problem3=(5, 1))
|
||||||
|
self.check('- long text:\n'
|
||||||
|
' "very \\"long\\"\n'
|
||||||
|
' \'string\' with\n'
|
||||||
|
'\n'
|
||||||
|
' paragraph gap, \\n and\n'
|
||||||
|
' spaces."\n', conf)
|
||||||
|
|
||||||
|
def test_paragraph_single_quoted(self):
|
||||||
|
conf = ('indentation: {spaces: 2}\n'
|
||||||
|
'document-start: disable\n')
|
||||||
|
self.check('- long text: \'very "long"\n'
|
||||||
|
' \'\'string\'\' with\n'
|
||||||
|
'\n'
|
||||||
|
' paragraph gap, \\n and\n'
|
||||||
|
' spaces.\'\n', conf)
|
||||||
|
self.check('- long text: \'very "long"\n'
|
||||||
|
' \'\'string\'\' with\n'
|
||||||
|
'\n'
|
||||||
|
' paragraph gap, \\n and\n'
|
||||||
|
' spaces.\'\n', conf,
|
||||||
|
problem1=(2, 5), problem2=(4, 5), problem3=(5, 5))
|
||||||
|
self.check('- long text: \'very "long"\n'
|
||||||
|
'\'\'string\'\' with\n'
|
||||||
|
'\n'
|
||||||
|
'paragraph gap, \\n and\n'
|
||||||
|
'spaces.\'\n', conf,
|
||||||
|
problem1=(2, 1), problem2=(4, 1), problem3=(5, 1))
|
||||||
|
self.check('- long text:\n'
|
||||||
|
' \'very "long"\n'
|
||||||
|
' \'\'string\'\' with\n'
|
||||||
|
'\n'
|
||||||
|
' paragraph gap, \\n and\n'
|
||||||
|
' spaces.\'\n', conf)
|
||||||
|
|
||||||
|
def test_paragraph_folded(self):
|
||||||
|
conf = ('indentation: {spaces: 2}\n'
|
||||||
|
'document-start: disable\n')
|
||||||
|
self.check('- long text: >\n'
|
||||||
|
' very "long"\n'
|
||||||
|
' \'string\' with\n'
|
||||||
|
'\n'
|
||||||
|
' paragraph gap, \\n and\n'
|
||||||
|
' spaces.\n', conf)
|
||||||
|
self.check('- long text: >\n'
|
||||||
|
' very "long"\n'
|
||||||
|
' \'string\' with\n'
|
||||||
|
'\n'
|
||||||
|
' paragraph gap, \\n and\n'
|
||||||
|
' spaces.\n', conf,
|
||||||
|
problem1=(3, 6), problem2=(5, 7), problem3=(6, 8))
|
||||||
|
|
||||||
|
def test_paragraph_literal(self):
|
||||||
|
conf = ('indentation: {spaces: 2}\n'
|
||||||
|
'document-start: disable\n')
|
||||||
|
self.check('- long text: |\n'
|
||||||
|
' very "long"\n'
|
||||||
|
' \'string\' with\n'
|
||||||
|
'\n'
|
||||||
|
' paragraph gap, \\n and\n'
|
||||||
|
' spaces.\n', conf)
|
||||||
|
self.check('- long text: |\n'
|
||||||
|
' very "long"\n'
|
||||||
|
' \'string\' with\n'
|
||||||
|
'\n'
|
||||||
|
' paragraph gap, \\n and\n'
|
||||||
|
' spaces.\n', conf,
|
||||||
|
problem1=(3, 6), problem2=(5, 7), problem3=(6, 8))
|
||||||
|
@ -35,6 +35,72 @@ class Parent(object):
|
|||||||
self.explicit_key = False
|
self.explicit_key = False
|
||||||
|
|
||||||
|
|
||||||
|
def check_scalar_indentation(conf, token, context):
|
||||||
|
if token.start_mark.line == token.end_mark.line:
|
||||||
|
return
|
||||||
|
|
||||||
|
if token.plain:
|
||||||
|
expected_indent = token.start_mark.column
|
||||||
|
elif token.style in ('"', "'"):
|
||||||
|
expected_indent = token.start_mark.column + 1
|
||||||
|
elif token.style in ('>', '|'):
|
||||||
|
if context['stack'][-1].type == B_SEQ:
|
||||||
|
# - >
|
||||||
|
# multi
|
||||||
|
# line
|
||||||
|
expected_indent = token.start_mark.column + conf['spaces']
|
||||||
|
elif context['stack'][-1].type == KEY:
|
||||||
|
assert context['stack'][-1].explicit_key
|
||||||
|
# - ? >
|
||||||
|
# multi-line
|
||||||
|
# key
|
||||||
|
# : >
|
||||||
|
# multi-line
|
||||||
|
# value
|
||||||
|
expected_indent = token.start_mark.column + conf['spaces']
|
||||||
|
elif context['stack'][-1].type == VAL:
|
||||||
|
if token.start_mark.line + 1 > context['cur_line']:
|
||||||
|
# - key:
|
||||||
|
# >
|
||||||
|
# multi
|
||||||
|
# line
|
||||||
|
expected_indent = context['stack'][-1].indent + conf['spaces']
|
||||||
|
elif context['stack'][-2].explicit_key:
|
||||||
|
# - ? key
|
||||||
|
# : >
|
||||||
|
# multi-line
|
||||||
|
# value
|
||||||
|
expected_indent = token.start_mark.column + conf['spaces']
|
||||||
|
else:
|
||||||
|
# - key: >
|
||||||
|
# multi
|
||||||
|
# line
|
||||||
|
expected_indent = context['stack'][-2].indent + conf['spaces']
|
||||||
|
else:
|
||||||
|
expected_indent = context['stack'][-1].indent + conf['spaces']
|
||||||
|
|
||||||
|
line_no = token.start_mark.line + 1
|
||||||
|
|
||||||
|
line_start = token.start_mark.pointer
|
||||||
|
while True:
|
||||||
|
line_start = token.start_mark.buffer.find(
|
||||||
|
'\n', line_start, token.end_mark.pointer - 1) + 1
|
||||||
|
if line_start == 0:
|
||||||
|
break
|
||||||
|
line_no += 1
|
||||||
|
|
||||||
|
indent = 0
|
||||||
|
while token.start_mark.buffer[line_start + indent] == ' ':
|
||||||
|
indent += 1
|
||||||
|
if token.start_mark.buffer[line_start + indent] == '\n':
|
||||||
|
continue
|
||||||
|
|
||||||
|
if indent != expected_indent:
|
||||||
|
yield LintProblem(line_no, indent + 1,
|
||||||
|
'wrong indentation: expected %d but found %d' %
|
||||||
|
(expected_indent, indent))
|
||||||
|
|
||||||
|
|
||||||
def check(conf, token, prev, next, context):
|
def check(conf, token, prev, next, context):
|
||||||
if 'stack' not in context:
|
if 'stack' not in context:
|
||||||
context['stack'] = [Parent(ROOT, 0)]
|
context['stack'] = [Parent(ROOT, 0)]
|
||||||
@ -42,11 +108,13 @@ def check(conf, token, prev, next, context):
|
|||||||
|
|
||||||
# Step 1: Lint
|
# Step 1: Lint
|
||||||
|
|
||||||
if (not isinstance(token, (yaml.StreamStartToken, yaml.StreamEndToken)) and
|
needs_lint = (
|
||||||
not isinstance(token, yaml.BlockEndToken) and
|
not isinstance(token, (yaml.StreamStartToken, yaml.StreamEndToken)) and
|
||||||
not (isinstance(token, yaml.ScalarToken) and token.value == '') and
|
not isinstance(token, yaml.BlockEndToken) and
|
||||||
token.start_mark.line + 1 > context['cur_line']):
|
not (isinstance(token, yaml.ScalarToken) and token.value == '') and
|
||||||
|
token.start_mark.line + 1 > context['cur_line'])
|
||||||
|
|
||||||
|
if needs_lint:
|
||||||
found_indentation = token.start_mark.column
|
found_indentation = token.start_mark.column
|
||||||
expected = context['stack'][-1].indent
|
expected = context['stack'][-1].indent
|
||||||
|
|
||||||
@ -63,10 +131,17 @@ def check(conf, token, prev, next, context):
|
|||||||
'wrong indentation: expected %d but found %d' %
|
'wrong indentation: expected %d but found %d' %
|
||||||
(expected, found_indentation))
|
(expected, found_indentation))
|
||||||
|
|
||||||
|
if isinstance(token, yaml.ScalarToken):
|
||||||
|
for problem in check_scalar_indentation(conf, token, context):
|
||||||
|
yield problem
|
||||||
|
|
||||||
|
# Step 2.a:
|
||||||
|
|
||||||
|
if needs_lint:
|
||||||
context['cur_line_indent'] = found_indentation
|
context['cur_line_indent'] = found_indentation
|
||||||
context['cur_line'] = token.end_mark.line + 1
|
context['cur_line'] = token.end_mark.line + 1
|
||||||
|
|
||||||
# Step 2: Update state
|
# Step 2.b: Update state
|
||||||
|
|
||||||
if isinstance(token, yaml.BlockMappingStartToken):
|
if isinstance(token, yaml.BlockMappingStartToken):
|
||||||
assert isinstance(next, yaml.KeyToken)
|
assert isinstance(next, yaml.KeyToken)
|
||||||
|
Loading…
Reference in New Issue
Block a user