empty-values: Add forbid-in-flow-mappings conf
This allows preventing implicit `null` from empty values in flow
mappings.
For example:
{a:}
{a:, b: 2}
{
a: {
b: ,
c: {
d: 4,
e:
}
},
f:
}
This commit is contained in:
@@ -20,112 +20,242 @@ from tests.common import RuleTestCase
|
|||||||
class EmptyValuesTestCase(RuleTestCase):
|
class EmptyValuesTestCase(RuleTestCase):
|
||||||
rule_id = 'empty-values'
|
rule_id = 'empty-values'
|
||||||
|
|
||||||
def test_disabled_globally(self):
|
def test_disabled(self):
|
||||||
conf = 'empty-values: disable'
|
conf = ('empty-values: disable\n'
|
||||||
|
'braces: disable\n'
|
||||||
|
'commas: disable\n')
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'foo:\n', conf)
|
'foo:\n', conf)
|
||||||
|
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'foo:\n'
|
'foo:\n'
|
||||||
' bar:\n', conf)
|
' bar:\n', conf)
|
||||||
|
self.check('---\n'
|
||||||
|
'{a:}\n', conf)
|
||||||
|
self.check('---\n'
|
||||||
|
'foo: {a:}\n', conf)
|
||||||
|
self.check('---\n'
|
||||||
|
'- {a:}\n'
|
||||||
|
'- {a:, b: 2}\n'
|
||||||
|
'- {a: 1, b:}\n'
|
||||||
|
'- {a: 1, b: , }\n', conf)
|
||||||
|
self.check('---\n'
|
||||||
|
'{a: {b: , c: {d: 4, e:}}, f:}\n', conf)
|
||||||
|
|
||||||
def test_disabled_forbid_in_block_mappings(self):
|
def test_in_block_mappings_disabled(self):
|
||||||
conf = 'empty-values: {forbid-in-block-mappings: false}'
|
conf = ('empty-values: {forbid-in-block-mappings: false,\n'
|
||||||
|
' forbid-in-flow-mappings: false}\n')
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'foo:\n', conf)
|
'foo:\n', conf)
|
||||||
|
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'foo:\n'
|
'foo:\n'
|
||||||
'bar: aaa\n', conf)
|
'bar: aaa\n', conf)
|
||||||
|
|
||||||
def test_single_line(self):
|
def test_in_block_mappings_single_line(self):
|
||||||
conf = 'empty-values: {forbid-in-block-mappings: true}\n'
|
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
|
||||||
|
' forbid-in-flow-mappings: false}\n')
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'implicitly-null:\n', conf, problem1=(2, 17))
|
'implicitly-null:\n', conf, problem1=(2, 17))
|
||||||
|
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'implicitly-null:with-colons:in-key:\n', conf,
|
'implicitly-null:with-colons:in-key:\n', conf,
|
||||||
problem1=(2, 36))
|
problem1=(2, 36))
|
||||||
|
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'implicitly-null:with-colons:in-key2:\n', conf,
|
'implicitly-null:with-colons:in-key2:\n', conf,
|
||||||
problem1=(2, 37))
|
problem1=(2, 37))
|
||||||
|
|
||||||
def test_enabled_all_lines(self):
|
def test_in_block_mappings_all_lines(self):
|
||||||
conf = 'empty-values: {forbid-in-block-mappings: true}\n'
|
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
|
||||||
|
' forbid-in-flow-mappings: false}\n')
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'foo:\n'
|
'foo:\n'
|
||||||
'bar:\n'
|
'bar:\n'
|
||||||
'foobar:\n', conf, problem1=(2, 5),
|
'foobar:\n', conf, problem1=(2, 5),
|
||||||
problem2=(3, 5), problem3=(4, 8))
|
problem2=(3, 5), problem3=(4, 8))
|
||||||
|
|
||||||
def test_enabled_explicit_end_of_document(self):
|
def test_in_block_mappings_explicit_end_of_document(self):
|
||||||
conf = 'empty-values: {forbid-in-block-mappings: true}\n'
|
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
|
||||||
|
' forbid-in-flow-mappings: false}\n')
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'foo:\n'
|
'foo:\n'
|
||||||
'...\n', conf, problem1=(2, 5))
|
'...\n', conf, problem1=(2, 5))
|
||||||
|
|
||||||
def test_enabled_not_end_of_document(self):
|
def test_in_block_mappings_not_end_of_document(self):
|
||||||
conf = 'empty-values: {forbid-in-block-mappings: true}\n'
|
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
|
||||||
|
' forbid-in-flow-mappings: false}\n')
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'foo:\n'
|
'foo:\n'
|
||||||
'bar:\n'
|
'bar:\n'
|
||||||
' aaa\n', conf, problem1=(2, 5))
|
' aaa\n', conf, problem1=(2, 5))
|
||||||
|
|
||||||
def test_enabled_different_level(self):
|
def test_in_block_mappings_different_level(self):
|
||||||
conf = 'empty-values: {forbid-in-block-mappings: true}\n'
|
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
|
||||||
|
' forbid-in-flow-mappings: false}\n')
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'foo:\n'
|
'foo:\n'
|
||||||
' bar:\n'
|
' bar:\n'
|
||||||
'aaa: bbb\n', conf, problem1=(3, 6))
|
'aaa: bbb\n', conf, problem1=(3, 6))
|
||||||
|
|
||||||
def test_enabled_empty_flow_mapping(self):
|
def test_in_block_mappings_empty_flow_mapping(self):
|
||||||
conf = 'empty-values: {forbid-in-block-mappings: true}\n'
|
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
|
||||||
|
' forbid-in-flow-mappings: false}\n'
|
||||||
|
'braces: disable\n'
|
||||||
|
'commas: disable\n')
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'foo: {a:}\n', conf)
|
'foo: {a:}\n', conf)
|
||||||
|
self.check('---\n'
|
||||||
|
'- {a:, b: 2}\n'
|
||||||
|
'- {a: 1, b:}\n'
|
||||||
|
'- {a: 1, b: , }\n', conf)
|
||||||
|
|
||||||
def test_enabled_empty_block_sequence(self):
|
def test_in_block_mappings_empty_block_sequence(self):
|
||||||
conf = 'empty-values: {forbid-in-block-mappings: true}\n'
|
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
|
||||||
|
' forbid-in-flow-mappings: false}\n')
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'foo:\n'
|
'foo:\n'
|
||||||
' -\n', conf)
|
' -\n', conf)
|
||||||
|
|
||||||
def test_enabled_not_empty_or_explicit_null(self):
|
def test_in_block_mappings_not_empty_or_explicit_null(self):
|
||||||
conf = 'empty-values: {forbid-in-block-mappings: true}\n'
|
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
|
||||||
|
' forbid-in-flow-mappings: false}\n')
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'foo:\n'
|
'foo:\n'
|
||||||
' bar:\n'
|
' bar:\n'
|
||||||
' aaa\n', conf)
|
' aaa\n', conf)
|
||||||
|
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'explicitly-null: null\n', conf)
|
'explicitly-null: null\n', conf)
|
||||||
|
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'explicitly-null:with-colons:in-key: null\n', conf)
|
'explicitly-null:with-colons:in-key: null\n', conf)
|
||||||
|
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'false-null: nulL\n', conf)
|
'false-null: nulL\n', conf)
|
||||||
|
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'empty-string: \'\'\n', conf)
|
'empty-string: \'\'\n', conf)
|
||||||
|
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'nullable-boolean: false\n', conf)
|
'nullable-boolean: false\n', conf)
|
||||||
|
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'nullable-int: 0\n', conf)
|
'nullable-int: 0\n', conf)
|
||||||
|
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'First occurrence: &anchor Foo\n'
|
'First occurrence: &anchor Foo\n'
|
||||||
'Second occurrence: *anchor\n', conf)
|
'Second occurrence: *anchor\n', conf)
|
||||||
|
|
||||||
def test_enabled_various_explicit_null(self):
|
def test_in_block_mappings_various_explicit_null(self):
|
||||||
conf = 'empty-values: {forbid-in-block-mappings: true}\n'
|
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
|
||||||
self.check('---\n'
|
' forbid-in-flow-mappings: false}\n')
|
||||||
'null-key1: {?: val}\n', conf)
|
|
||||||
|
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'null-alias: ~\n', conf)
|
'null-alias: ~\n', conf)
|
||||||
|
self.check('---\n'
|
||||||
|
'null-key1: {?: val}\n', conf)
|
||||||
self.check('---\n'
|
self.check('---\n'
|
||||||
'null-key2: {? !!null "": val}\n', conf)
|
'null-key2: {? !!null "": val}\n', conf)
|
||||||
|
|
||||||
|
def test_in_block_mappings_comments(self):
|
||||||
|
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
|
||||||
|
' forbid-in-flow-mappings: false}\n'
|
||||||
|
'comments: disable\n')
|
||||||
|
self.check('---\n'
|
||||||
|
'empty: # comment\n'
|
||||||
|
'foo:\n'
|
||||||
|
' bar: # comment\n', conf,
|
||||||
|
problem1=(2, 7),
|
||||||
|
problem2=(4, 7))
|
||||||
|
|
||||||
|
def test_in_flow_mappings_disabled(self):
|
||||||
|
conf = ('empty-values: {forbid-in-block-mappings: false,\n'
|
||||||
|
' forbid-in-flow-mappings: false}\n'
|
||||||
|
'braces: disable\n'
|
||||||
|
'commas: disable\n')
|
||||||
|
self.check('---\n'
|
||||||
|
'{a:}\n', conf)
|
||||||
|
self.check('---\n'
|
||||||
|
'foo: {a:}\n', conf)
|
||||||
|
self.check('---\n'
|
||||||
|
'- {a:}\n'
|
||||||
|
'- {a:, b: 2}\n'
|
||||||
|
'- {a: 1, b:}\n'
|
||||||
|
'- {a: 1, b: , }\n', conf)
|
||||||
|
self.check('---\n'
|
||||||
|
'{a: {b: , c: {d: 4, e:}}, f:}\n', conf)
|
||||||
|
|
||||||
|
def test_in_flow_mappings_single_line(self):
|
||||||
|
conf = ('empty-values: {forbid-in-block-mappings: false,\n'
|
||||||
|
' forbid-in-flow-mappings: true}\n'
|
||||||
|
'braces: disable\n'
|
||||||
|
'commas: disable\n')
|
||||||
|
self.check('---\n'
|
||||||
|
'{a:}\n', conf,
|
||||||
|
problem=(2, 4))
|
||||||
|
self.check('---\n'
|
||||||
|
'foo: {a:}\n', conf,
|
||||||
|
problem=(2, 9))
|
||||||
|
self.check('---\n'
|
||||||
|
'- {a:}\n'
|
||||||
|
'- {a:, b: 2}\n'
|
||||||
|
'- {a: 1, b:}\n'
|
||||||
|
'- {a: 1, b: , }\n', conf,
|
||||||
|
problem1=(2, 6),
|
||||||
|
problem2=(3, 6),
|
||||||
|
problem3=(4, 12),
|
||||||
|
problem4=(5, 12))
|
||||||
|
self.check('---\n'
|
||||||
|
'{a: {b: , c: {d: 4, e:}}, f:}\n', conf,
|
||||||
|
problem1=(2, 8),
|
||||||
|
problem2=(2, 23),
|
||||||
|
problem3=(2, 29))
|
||||||
|
|
||||||
|
def test_in_flow_mappings_multi_line(self):
|
||||||
|
conf = ('empty-values: {forbid-in-block-mappings: false,\n'
|
||||||
|
' forbid-in-flow-mappings: true}\n'
|
||||||
|
'braces: disable\n'
|
||||||
|
'commas: disable\n')
|
||||||
|
self.check('---\n'
|
||||||
|
'foo: {\n'
|
||||||
|
' a:\n'
|
||||||
|
'}\n', conf,
|
||||||
|
problem=(3, 5))
|
||||||
|
self.check('---\n'
|
||||||
|
'{\n'
|
||||||
|
' a: {\n'
|
||||||
|
' b: ,\n'
|
||||||
|
' c: {\n'
|
||||||
|
' d: 4,\n'
|
||||||
|
' e:\n'
|
||||||
|
' }\n'
|
||||||
|
' },\n'
|
||||||
|
' f:\n'
|
||||||
|
'}\n', conf,
|
||||||
|
problem1=(4, 7),
|
||||||
|
problem2=(7, 9),
|
||||||
|
problem3=(10, 5))
|
||||||
|
|
||||||
|
def test_in_flow_mappings_various_explicit_null(self):
|
||||||
|
conf = ('empty-values: {forbid-in-block-mappings: false,\n'
|
||||||
|
' forbid-in-flow-mappings: true}\n'
|
||||||
|
'braces: disable\n'
|
||||||
|
'commas: disable\n')
|
||||||
|
self.check('---\n'
|
||||||
|
'{explicit-null: null}\n', conf)
|
||||||
|
self.check('---\n'
|
||||||
|
'{null-alias: ~}\n', conf)
|
||||||
|
self.check('---\n'
|
||||||
|
'null-key1: {?: val}\n', conf)
|
||||||
|
self.check('---\n'
|
||||||
|
'null-key2: {? !!null "": val}\n', conf)
|
||||||
|
|
||||||
|
def test_in_flow_mappings_comments(self):
|
||||||
|
conf = ('empty-values: {forbid-in-block-mappings: false,\n'
|
||||||
|
' forbid-in-flow-mappings: true}\n'
|
||||||
|
'braces: disable\n'
|
||||||
|
'commas: disable\n'
|
||||||
|
'comments: disable\n')
|
||||||
|
self.check('---\n'
|
||||||
|
'{\n'
|
||||||
|
' a: {\n'
|
||||||
|
' b: , # comment\n'
|
||||||
|
' c: {\n'
|
||||||
|
' d: 4, # comment\n'
|
||||||
|
' e: # comment\n'
|
||||||
|
' }\n'
|
||||||
|
' },\n'
|
||||||
|
' f: # comment\n'
|
||||||
|
'}\n', conf,
|
||||||
|
problem1=(4, 7),
|
||||||
|
problem2=(7, 9),
|
||||||
|
problem3=(10, 5))
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ rules:
|
|||||||
max-end: 0
|
max-end: 0
|
||||||
empty-values:
|
empty-values:
|
||||||
forbid-in-block-mappings: false
|
forbid-in-block-mappings: false
|
||||||
|
forbid-in-flow-mappings: false
|
||||||
hyphens:
|
hyphens:
|
||||||
max-spaces-after: 1
|
max-spaces-after: 1
|
||||||
indentation:
|
indentation:
|
||||||
|
|||||||
@@ -20,12 +20,13 @@ Use this rule to prevent nodes with empty content, that implicitly result in
|
|||||||
|
|
||||||
.. rubric:: Options
|
.. rubric:: Options
|
||||||
|
|
||||||
* Use ``forbid-in-block-mappings`` to prevent implicit empty values in block
|
* Use ``forbid-in-block-mappings`` to prevent empty values in block mappings.
|
||||||
mappings.
|
* Use ``forbid-in-flow-mappings`` to prevent empty values in flow mappings.
|
||||||
|
|
||||||
.. rubric:: Examples
|
.. rubric:: Examples
|
||||||
|
|
||||||
#. With ``empty-values: {forbid-in-block-mappings: true}``
|
#. With ``empty-values: {forbid-in-block-mappings: true}``
|
||||||
|
|
||||||
the following code snippets would **PASS**:
|
the following code snippets would **PASS**:
|
||||||
::
|
::
|
||||||
|
|
||||||
@@ -46,6 +47,23 @@ Use this rule to prevent nodes with empty content, that implicitly result in
|
|||||||
|
|
||||||
implicitly-null:
|
implicitly-null:
|
||||||
|
|
||||||
|
#. With ``empty-values: {forbid-in-flow-mappings: true}``
|
||||||
|
|
||||||
|
the following code snippet would **PASS**:
|
||||||
|
::
|
||||||
|
|
||||||
|
{prop: null}
|
||||||
|
{a: 1, b: 2, c: 3}
|
||||||
|
|
||||||
|
the following code snippets would **FAIL**:
|
||||||
|
::
|
||||||
|
|
||||||
|
{prop: }
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
{a: 1, b:, c: 3}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
@@ -55,15 +73,22 @@ from yamllint.linter import LintProblem
|
|||||||
|
|
||||||
ID = 'empty-values'
|
ID = 'empty-values'
|
||||||
TYPE = 'token'
|
TYPE = 'token'
|
||||||
CONF = {'forbid-in-block-mappings': bool}
|
CONF = {'forbid-in-block-mappings': bool,
|
||||||
|
'forbid-in-flow-mappings': bool}
|
||||||
|
|
||||||
|
|
||||||
def check(conf, token, prev, next, nextnext, context):
|
def check(conf, token, prev, next, nextnext, context):
|
||||||
|
|
||||||
if conf['forbid-in-block-mappings']:
|
if conf['forbid-in-block-mappings']:
|
||||||
if isinstance(token, yaml.ValueToken) and isinstance(next, (
|
if isinstance(token, yaml.ValueToken) and isinstance(next, (
|
||||||
yaml.KeyToken, yaml.BlockEndToken,
|
yaml.KeyToken, yaml.BlockEndToken)):
|
||||||
yaml.StreamEndToken, yaml.DocumentEndToken)):
|
|
||||||
yield LintProblem(token.start_mark.line + 1,
|
yield LintProblem(token.start_mark.line + 1,
|
||||||
token.end_mark.column + 1,
|
token.end_mark.column + 1,
|
||||||
'empty value in block mapping')
|
'empty value in block mapping')
|
||||||
|
|
||||||
|
if conf['forbid-in-flow-mappings']:
|
||||||
|
if isinstance(token, yaml.ValueToken) and isinstance(next, (
|
||||||
|
yaml.FlowEntryToken, yaml.FlowMappingEndToken)):
|
||||||
|
yield LintProblem(token.start_mark.line + 1,
|
||||||
|
token.end_mark.column + 1,
|
||||||
|
'empty value in flow mapping')
|
||||||
|
|||||||
Reference in New Issue
Block a user