quoted-strings: Add allow-quoted-quotes option
Allows strings like `'foo"bar'` on `quote-type: double` and vice versa.
This commit is contained in:
@@ -453,3 +453,106 @@ class QuotedTestCase(RuleTestCase):
|
|||||||
'- "0o800"\n',
|
'- "0o800"\n',
|
||||||
conf,
|
conf,
|
||||||
problem1=(9, 3), problem2=(10, 3))
|
problem1=(9, 3), problem2=(10, 3))
|
||||||
|
|
||||||
|
def test_allow_quoted_quotes(self):
|
||||||
|
conf = ('quoted-strings: {quote-type: single,\n'
|
||||||
|
' required: false,\n'
|
||||||
|
' allow-quoted-quotes: false}\n')
|
||||||
|
self.check('---\n'
|
||||||
|
'foo1: "[barbaz]"\n' # fails
|
||||||
|
'foo2: "[bar\'baz]"\n', # fails
|
||||||
|
conf, problem1=(2, 7), problem2=(3, 7))
|
||||||
|
|
||||||
|
conf = ('quoted-strings: {quote-type: single,\n'
|
||||||
|
' required: false,\n'
|
||||||
|
' allow-quoted-quotes: true}\n')
|
||||||
|
self.check('---\n'
|
||||||
|
'foo1: "[barbaz]"\n' # fails
|
||||||
|
'foo2: "[bar\'baz]"\n',
|
||||||
|
conf, problem1=(2, 7))
|
||||||
|
|
||||||
|
conf = ('quoted-strings: {quote-type: single,\n'
|
||||||
|
' required: true,\n'
|
||||||
|
' allow-quoted-quotes: false}\n')
|
||||||
|
self.check('---\n'
|
||||||
|
'foo1: "[barbaz]"\n' # fails
|
||||||
|
'foo2: "[bar\'baz]"\n', # fails
|
||||||
|
conf, problem1=(2, 7), problem2=(3, 7))
|
||||||
|
|
||||||
|
conf = ('quoted-strings: {quote-type: single,\n'
|
||||||
|
' required: true,\n'
|
||||||
|
' allow-quoted-quotes: true}\n')
|
||||||
|
self.check('---\n'
|
||||||
|
'foo1: "[barbaz]"\n' # fails
|
||||||
|
'foo2: "[bar\'baz]"\n',
|
||||||
|
conf, problem1=(2, 7))
|
||||||
|
|
||||||
|
conf = ('quoted-strings: {quote-type: single,\n'
|
||||||
|
' required: only-when-needed,\n'
|
||||||
|
' allow-quoted-quotes: false}\n')
|
||||||
|
self.check('---\n'
|
||||||
|
'foo1: "[barbaz]"\n' # fails
|
||||||
|
'foo2: "[bar\'baz]"\n', # fails
|
||||||
|
conf, problem1=(2, 7), problem2=(3, 7))
|
||||||
|
|
||||||
|
conf = ('quoted-strings: {quote-type: single,\n'
|
||||||
|
' required: only-when-needed,\n'
|
||||||
|
' allow-quoted-quotes: true}\n')
|
||||||
|
self.check('---\n'
|
||||||
|
'foo1: "[barbaz]"\n' # fails
|
||||||
|
'foo2: "[bar\'baz]"\n',
|
||||||
|
conf, problem1=(2, 7))
|
||||||
|
|
||||||
|
conf = ('quoted-strings: {quote-type: double,\n'
|
||||||
|
' required: false,\n'
|
||||||
|
' allow-quoted-quotes: false}\n')
|
||||||
|
self.check("---\n"
|
||||||
|
"foo1: '[barbaz]'\n" # fails
|
||||||
|
"foo2: '[bar\"baz]'\n", # fails
|
||||||
|
conf, problem1=(2, 7), problem2=(3, 7))
|
||||||
|
|
||||||
|
conf = ('quoted-strings: {quote-type: double,\n'
|
||||||
|
' required: false,\n'
|
||||||
|
' allow-quoted-quotes: true}\n')
|
||||||
|
self.check("---\n"
|
||||||
|
"foo1: '[barbaz]'\n" # fails
|
||||||
|
"foo2: '[bar\"baz]'\n",
|
||||||
|
conf, problem1=(2, 7))
|
||||||
|
|
||||||
|
conf = ('quoted-strings: {quote-type: double,\n'
|
||||||
|
' required: true,\n'
|
||||||
|
' allow-quoted-quotes: false}\n')
|
||||||
|
self.check("---\n"
|
||||||
|
"foo1: '[barbaz]'\n" # fails
|
||||||
|
"foo2: '[bar\"baz]'\n", # fails
|
||||||
|
conf, problem1=(2, 7), problem2=(3, 7))
|
||||||
|
|
||||||
|
conf = ('quoted-strings: {quote-type: double,\n'
|
||||||
|
' required: true,\n'
|
||||||
|
' allow-quoted-quotes: true}\n')
|
||||||
|
self.check("---\n"
|
||||||
|
"foo1: '[barbaz]'\n" # fails
|
||||||
|
"foo2: '[bar\"baz]'\n",
|
||||||
|
conf, problem1=(2, 7))
|
||||||
|
|
||||||
|
conf = ('quoted-strings: {quote-type: double,\n'
|
||||||
|
' required: only-when-needed,\n'
|
||||||
|
' allow-quoted-quotes: false}\n')
|
||||||
|
self.check("---\n"
|
||||||
|
"foo1: '[barbaz]'\n" # fails
|
||||||
|
"foo2: '[bar\"baz]'\n", # fails
|
||||||
|
conf, problem1=(2, 7), problem2=(3, 7))
|
||||||
|
|
||||||
|
conf = ('quoted-strings: {quote-type: double,\n'
|
||||||
|
' required: only-when-needed,\n'
|
||||||
|
' allow-quoted-quotes: true}\n')
|
||||||
|
self.check("---\n"
|
||||||
|
"foo1: '[barbaz]'\n" # fails
|
||||||
|
"foo2: '[bar\"baz]'\n",
|
||||||
|
conf, problem1=(2, 7))
|
||||||
|
|
||||||
|
conf = ('quoted-strings: {quote-type: any}\n')
|
||||||
|
self.check("---\n"
|
||||||
|
"foo1: '[barbaz]'\n"
|
||||||
|
"foo2: '[bar\"baz]'\n",
|
||||||
|
conf)
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ used.
|
|||||||
``required: false`` and ``required: only-when-needed``.
|
``required: false`` and ``required: only-when-needed``.
|
||||||
* ``extra-allowed`` is a list of PCRE regexes to allow quoted string values,
|
* ``extra-allowed`` is a list of PCRE regexes to allow quoted string values,
|
||||||
even if ``required: only-when-needed`` is set.
|
even if ``required: only-when-needed`` is set.
|
||||||
|
* ``allow-quoted-quotes`` allows (``true``) using disallowed quotes for strings
|
||||||
|
with allowed quotes inside. Default ``false``.
|
||||||
|
|
||||||
**Note**: Multi-line strings (with ``|`` or ``>``) will not be checked.
|
**Note**: Multi-line strings (with ``|`` or ``>``) will not be checked.
|
||||||
|
|
||||||
@@ -43,6 +45,7 @@ used.
|
|||||||
required: true
|
required: true
|
||||||
extra-required: []
|
extra-required: []
|
||||||
extra-allowed: []
|
extra-allowed: []
|
||||||
|
allow-quoted-quotes: false
|
||||||
|
|
||||||
.. rubric:: Examples
|
.. rubric:: Examples
|
||||||
|
|
||||||
@@ -112,6 +115,26 @@ used.
|
|||||||
|
|
||||||
- "localhost"
|
- "localhost"
|
||||||
- this is a string that needs to be QUOTED
|
- this is a string that needs to be QUOTED
|
||||||
|
|
||||||
|
#. With ``quoted-strings: {quote-type: double, allow-quoted-quotes: false}``
|
||||||
|
|
||||||
|
the following code snippet would **PASS**:
|
||||||
|
::
|
||||||
|
|
||||||
|
foo: "bar\"baz"
|
||||||
|
|
||||||
|
the following code snippet would **FAIL**:
|
||||||
|
::
|
||||||
|
|
||||||
|
foo: 'bar"baz'
|
||||||
|
|
||||||
|
#. With ``quoted-strings: {quote-type: double, allow-quoted-quotes: true}``
|
||||||
|
|
||||||
|
the following code snippet would **PASS**:
|
||||||
|
::
|
||||||
|
|
||||||
|
foo: 'bar"baz'
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
@@ -125,11 +148,13 @@ TYPE = 'token'
|
|||||||
CONF = {'quote-type': ('any', 'single', 'double'),
|
CONF = {'quote-type': ('any', 'single', 'double'),
|
||||||
'required': (True, False, 'only-when-needed'),
|
'required': (True, False, 'only-when-needed'),
|
||||||
'extra-required': [str],
|
'extra-required': [str],
|
||||||
'extra-allowed': [str]}
|
'extra-allowed': [str],
|
||||||
|
'allow-quoted-quotes': bool}
|
||||||
DEFAULT = {'quote-type': 'any',
|
DEFAULT = {'quote-type': 'any',
|
||||||
'required': True,
|
'required': True,
|
||||||
'extra-required': [],
|
'extra-required': [],
|
||||||
'extra-allowed': []}
|
'extra-allowed': [],
|
||||||
|
'allow-quoted-quotes': False}
|
||||||
|
|
||||||
|
|
||||||
def VALIDATE(conf):
|
def VALIDATE(conf):
|
||||||
@@ -177,6 +202,12 @@ def _quotes_are_needed(string):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _has_quoted_quotes(token):
|
||||||
|
return ((not token.plain) and
|
||||||
|
((token.style == "'" and '"' in token.value) or
|
||||||
|
(token.style == '"' and "'" in token.value)))
|
||||||
|
|
||||||
|
|
||||||
def check(conf, token, prev, next, nextnext, context):
|
def check(conf, token, prev, next, nextnext, context):
|
||||||
if not (isinstance(token, yaml.tokens.ScalarToken) and
|
if not (isinstance(token, yaml.tokens.ScalarToken) and
|
||||||
isinstance(prev, (yaml.BlockEntryToken, yaml.FlowEntryToken,
|
isinstance(prev, (yaml.BlockEntryToken, yaml.FlowEntryToken,
|
||||||
@@ -206,13 +237,18 @@ def check(conf, token, prev, next, nextnext, context):
|
|||||||
if conf['required'] is True:
|
if conf['required'] is True:
|
||||||
|
|
||||||
# Quotes are mandatory and need to match config
|
# Quotes are mandatory and need to match config
|
||||||
if token.style is None or not _quote_match(quote_type, token.style):
|
if (token.style is None or
|
||||||
|
not (_quote_match(quote_type, token.style) or
|
||||||
|
(conf['allow-quoted-quotes'] and _has_quoted_quotes(token)))):
|
||||||
msg = "string value is not quoted with %s quotes" % quote_type
|
msg = "string value is not quoted with %s quotes" % quote_type
|
||||||
|
|
||||||
elif conf['required'] is False:
|
elif conf['required'] is False:
|
||||||
|
|
||||||
# Quotes are not mandatory but when used need to match config
|
# Quotes are not mandatory but when used need to match config
|
||||||
if token.style and not _quote_match(quote_type, token.style):
|
if (token.style and
|
||||||
|
not _quote_match(quote_type, token.style) and
|
||||||
|
not (conf['allow-quoted-quotes'] and
|
||||||
|
_has_quoted_quotes(token))):
|
||||||
msg = "string value is not quoted with %s quotes" % quote_type
|
msg = "string value is not quoted with %s quotes" % quote_type
|
||||||
|
|
||||||
elif not token.style:
|
elif not token.style:
|
||||||
@@ -235,7 +271,9 @@ def check(conf, token, prev, next, nextnext, context):
|
|||||||
quote_type)
|
quote_type)
|
||||||
|
|
||||||
# But when used need to match config
|
# But when used need to match config
|
||||||
elif token.style and not _quote_match(quote_type, token.style):
|
elif (token.style and
|
||||||
|
not _quote_match(quote_type, token.style) and
|
||||||
|
not (conf['allow-quoted-quotes'] and _has_quoted_quotes(token))):
|
||||||
msg = "string value is not quoted with %s quotes" % quote_type
|
msg = "string value is not quoted with %s quotes" % quote_type
|
||||||
|
|
||||||
elif not token.style:
|
elif not token.style:
|
||||||
|
|||||||
Reference in New Issue
Block a user