Initial commit
This commit is contained in:
80
yamllint/__init__.py
Normal file
80
yamllint/__init__.py
Normal file
@@ -0,0 +1,80 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2016 Adrien Vergé
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from yamllint import config
|
||||
from yamllint import parser
|
||||
|
||||
|
||||
APP_NAME = 'yamllint'
|
||||
APP_VERSION = '0.1.0'
|
||||
APP_DESCRIPTION = 'Lint YAML files.'
|
||||
|
||||
__author__ = 'Adrien Vergé'
|
||||
__copyright__ = 'Copyright 2016, Adrien Vergé'
|
||||
__license__ = 'GPLv3'
|
||||
__version__ = APP_VERSION
|
||||
|
||||
|
||||
def _lint(buffer, conf):
|
||||
rules = config.get_enabled_rules(conf)
|
||||
|
||||
# Split token rules from line rules
|
||||
token_rules = [r for r in rules if r.TYPE == 'token']
|
||||
line_rules = [r for r in rules if r.TYPE == 'line']
|
||||
|
||||
# If the document contains a syntax error, save it and yield it at the
|
||||
# right line
|
||||
syntax_error = parser.get_syntax_error(buffer)
|
||||
|
||||
for elem in parser.token_or_line_generator(buffer):
|
||||
if syntax_error and syntax_error.line <= elem.line_no:
|
||||
syntax_error.level = 'error'
|
||||
yield syntax_error
|
||||
syntax_error = None
|
||||
|
||||
if isinstance(elem, parser.Token):
|
||||
for rule in token_rules:
|
||||
rule_conf = conf[rule.ID]
|
||||
for problem in rule.check(rule_conf,
|
||||
elem.curr, elem.prev, elem.next):
|
||||
problem.rule = rule.ID
|
||||
problem.level = rule_conf['level']
|
||||
yield problem
|
||||
elif isinstance(elem, parser.Line):
|
||||
for rule in line_rules:
|
||||
rule_conf = conf[rule.ID]
|
||||
for problem in rule.check(rule_conf, elem):
|
||||
problem.rule = rule.ID
|
||||
problem.level = rule_conf['level']
|
||||
yield problem
|
||||
|
||||
|
||||
def lint(input, conf):
|
||||
"""Lints a YAML source.
|
||||
|
||||
Returns a generator of LintProblem objects.
|
||||
|
||||
:param input: buffer, string or stream to read from
|
||||
:param conf: yamllint configuration object
|
||||
"""
|
||||
if type(input) == str:
|
||||
return _lint(input, conf)
|
||||
elif hasattr(input, 'read'): # Python 2's file or Python 3's io.IOBase
|
||||
# We need to have everything in memory to parse correctly
|
||||
content = input.read()
|
||||
return _lint(content, conf)
|
||||
else:
|
||||
raise TypeError('input should be a string or a stream')
|
||||
39
yamllint/conf/default.yml
Normal file
39
yamllint/conf/default.yml
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
|
||||
rules:
|
||||
#block-sequence-indentation:
|
||||
# present: yes
|
||||
colons:
|
||||
max-spaces-before: 0
|
||||
max-spaces-after: 1
|
||||
#comma:
|
||||
# max-spaces-before: 0
|
||||
# max-spaces-after: 1
|
||||
#comment:
|
||||
# min-spaces-after: 1
|
||||
# min-spaces-before: 2
|
||||
document-end: disable
|
||||
document-start:
|
||||
level: warning
|
||||
present: yes
|
||||
empty-lines:
|
||||
max: 2
|
||||
max-start: 0
|
||||
max-end: 0
|
||||
hyphens:
|
||||
max-spaces-after: 1
|
||||
indentation:
|
||||
spaces: 2
|
||||
#comments: yes
|
||||
line-length:
|
||||
max: 80
|
||||
new-line-at-end-of-file: {level: error}
|
||||
new-lines:
|
||||
type: unix
|
||||
#spaces-in-brackets: [ 1, 2 ]
|
||||
# min: 1
|
||||
# max: 1
|
||||
#spaces-in-braces: { df: d }
|
||||
# min: 1
|
||||
# max: 1
|
||||
trailing-spaces: {}
|
||||
103
yamllint/config.py
Normal file
103
yamllint/config.py
Normal file
@@ -0,0 +1,103 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2016 Adrien Vergé
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os.path
|
||||
|
||||
import yaml
|
||||
|
||||
import yamllint.rules
|
||||
from yamllint.errors import YamlLintConfigError
|
||||
|
||||
|
||||
def get_extended_conf(name):
|
||||
# Is it a standard conf shipped with yamllint...
|
||||
if '/' not in name:
|
||||
std_conf = os.path.join(os.path.dirname(os.path.realpath(__file__)),
|
||||
'conf', name + '.yml')
|
||||
|
||||
if os.path.isfile(std_conf):
|
||||
return std_conf
|
||||
|
||||
# or a custom conf on filesystem?
|
||||
return name
|
||||
|
||||
|
||||
def extend_config(content):
|
||||
try:
|
||||
conf = yaml.safe_load(content)
|
||||
|
||||
if 'rules' not in conf:
|
||||
conf['rules'] = {}
|
||||
|
||||
# Does this conf override another conf that we need to load?
|
||||
if 'extends' in conf:
|
||||
base = parse_config_from_file(get_extended_conf(conf['extends']))
|
||||
|
||||
base.update(conf['rules'])
|
||||
conf['rules'] = base
|
||||
|
||||
return conf
|
||||
except Exception as e:
|
||||
raise YamlLintConfigError('invalid config: %s' % e)
|
||||
|
||||
|
||||
def parse_config(content):
|
||||
conf = extend_config(content)
|
||||
rules = {}
|
||||
|
||||
for id in conf['rules']:
|
||||
try:
|
||||
rule = yamllint.rules.get(id)
|
||||
except Exception as e:
|
||||
raise YamlLintConfigError('invalid config: %s' % e)
|
||||
|
||||
if conf['rules'][id] == 'disable':
|
||||
continue
|
||||
|
||||
rules[id] = {'level': 'error'}
|
||||
if type(conf['rules'][id]) == dict:
|
||||
if 'level' in conf['rules'][id]:
|
||||
if conf['rules'][id]['level'] not in ('error', 'warning'):
|
||||
raise YamlLintConfigError(
|
||||
'invalid config: level should be "error" or "warning"')
|
||||
rules[id]['level'] = conf['rules'][id]['level']
|
||||
|
||||
options = getattr(rule, 'CONF', {})
|
||||
for optkey in conf['rules'][id]:
|
||||
if optkey == 'level':
|
||||
continue
|
||||
if optkey not in options:
|
||||
raise YamlLintConfigError(
|
||||
'invalid config: unknown option "%s" for rule "%s"' %
|
||||
(optkey, id))
|
||||
if type(conf['rules'][id][optkey]) != options[optkey]:
|
||||
raise YamlLintConfigError(
|
||||
'invalid config: option "%s" of "%s" should be %s' %
|
||||
(optkey, id, options[optkey].__name__))
|
||||
rules[id][optkey] = conf['rules'][id][optkey]
|
||||
else:
|
||||
raise YamlLintConfigError(('invalid config: rule "%s": should be '
|
||||
'either "disable" or a dict') % id)
|
||||
return rules
|
||||
|
||||
|
||||
def parse_config_from_file(path):
|
||||
with open(path) as f:
|
||||
return parse_config(f.read())
|
||||
|
||||
|
||||
def get_enabled_rules(conf):
|
||||
return [yamllint.rules.get(r) for r in conf.keys() if conf[r] is not False]
|
||||
50
yamllint/errors.py
Normal file
50
yamllint/errors.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2016 Adrien Vergé
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
class LintProblem(object):
|
||||
def __init__(self, line, column, desc='<no description>', rule=None):
|
||||
self.line = line
|
||||
self.column = column
|
||||
self.desc = desc
|
||||
self.rule = rule
|
||||
self.level = None
|
||||
|
||||
@property
|
||||
def message(self):
|
||||
if self.rule is not None:
|
||||
return '%s (%s)' % (self.desc, self.rule)
|
||||
return self.desc
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.line == other.line and
|
||||
self.column == other.column and
|
||||
self.rule == other.rule)
|
||||
|
||||
def __lt__(self, other):
|
||||
return (self.line < other.line or
|
||||
(self.line == other.line and self.column < other.column))
|
||||
|
||||
def __repr__(self):
|
||||
return '%d:%d: %s' % (self.line, self.column, self.message)
|
||||
|
||||
|
||||
class YamlLintError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class YamlLintConfigError(YamlLintError):
|
||||
pass
|
||||
38
yamllint/output.py
Normal file
38
yamllint/output.py
Normal file
@@ -0,0 +1,38 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2016 Adrien Vergé
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
def parsable_format(problem, filename):
|
||||
return ('%(file)s:%(line)s:%(column)s: [%(level)s] %(message)s' %
|
||||
{'file': filename,
|
||||
'line': problem.line,
|
||||
'column': problem.column,
|
||||
'level': problem.level,
|
||||
'message': problem.message})
|
||||
|
||||
|
||||
def standard_format(problem, filename):
|
||||
line = ' \033[2m%d:%d\033[0m' % (problem.line, problem.column)
|
||||
line += max(20 - len(line), 0) * ' '
|
||||
if problem.level == 'warning':
|
||||
line += '\033[33m%s\033[0m' % problem.level
|
||||
else:
|
||||
line += '\033[31m%s\033[0m' % problem.level
|
||||
line += max(38 - len(line), 0) * ' '
|
||||
line += problem.desc
|
||||
if problem.rule:
|
||||
line += ' \033[2m(%s)\033[0m' % problem.rule
|
||||
return line
|
||||
95
yamllint/parser.py
Normal file
95
yamllint/parser.py
Normal file
@@ -0,0 +1,95 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2016 Adrien Vergé
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import yaml
|
||||
|
||||
from yamllint.errors import LintProblem
|
||||
|
||||
|
||||
class Line(object):
|
||||
def __init__(self, line_no, buffer, start, end):
|
||||
self.line_no = line_no
|
||||
self.start = start
|
||||
self.end = end
|
||||
self.buffer = buffer
|
||||
|
||||
@property
|
||||
def content(self):
|
||||
return self.buffer[self.start:self.end]
|
||||
|
||||
|
||||
class Token(object):
|
||||
def __init__(self, line_no, curr, prev, next):
|
||||
self.line_no = line_no
|
||||
self.curr = curr
|
||||
self.prev = prev
|
||||
self.next = next
|
||||
|
||||
|
||||
def line_generator(buffer):
|
||||
line_no = 1
|
||||
cur = 0
|
||||
next = buffer.find('\n')
|
||||
while next != -1:
|
||||
yield Line(line_no, buffer, start=cur, end=next)
|
||||
cur = next + 1
|
||||
next = buffer.find('\n', cur)
|
||||
line_no += 1
|
||||
|
||||
yield Line(line_no, buffer, start=cur, end=len(buffer))
|
||||
|
||||
|
||||
def token_generator(buffer):
|
||||
yaml_loader = yaml.BaseLoader(buffer)
|
||||
|
||||
try:
|
||||
prev = None
|
||||
next = yaml_loader.peek_token()
|
||||
while next is not None:
|
||||
curr = yaml_loader.get_token()
|
||||
next = yaml_loader.peek_token()
|
||||
|
||||
yield Token(curr.start_mark.line + 1, curr, prev, next)
|
||||
|
||||
prev = curr
|
||||
except yaml.scanner.ScannerError:
|
||||
pass
|
||||
|
||||
|
||||
def token_or_line_generator(buffer):
|
||||
"""Generator that mixes tokens and lines, ordering them by line number"""
|
||||
token_gen = token_generator(buffer)
|
||||
line_gen = line_generator(buffer)
|
||||
|
||||
token = next(token_gen, None)
|
||||
line = next(line_gen, None)
|
||||
|
||||
while token is not None or line is not None:
|
||||
if token is None or (line is not None and
|
||||
token.line_no > line.line_no):
|
||||
yield line
|
||||
line = next(line_gen, None)
|
||||
else:
|
||||
yield token
|
||||
token = next(token_gen, None)
|
||||
|
||||
|
||||
def get_syntax_error(buffer):
|
||||
try:
|
||||
yaml.safe_load_all(buffer)
|
||||
except yaml.error.MarkedYAMLError as e:
|
||||
return LintProblem(e.problem_mark.line + 1, e.problem_mark.column + 1,
|
||||
'syntax error: ' + e.problem)
|
||||
48
yamllint/rules/__init__.py
Normal file
48
yamllint/rules/__init__.py
Normal file
@@ -0,0 +1,48 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2016 Adrien Vergé
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from yamllint.rules import (
|
||||
colons,
|
||||
document_end,
|
||||
document_start,
|
||||
empty_lines,
|
||||
hyphens,
|
||||
indentation,
|
||||
line_length,
|
||||
new_line_at_end_of_file,
|
||||
new_lines,
|
||||
trailing_spaces,
|
||||
)
|
||||
|
||||
_RULES = {
|
||||
colons.ID: colons,
|
||||
document_end.ID: document_end,
|
||||
document_start.ID: document_start,
|
||||
empty_lines.ID: empty_lines,
|
||||
hyphens.ID: hyphens,
|
||||
indentation.ID: indentation,
|
||||
line_length.ID: line_length,
|
||||
new_line_at_end_of_file.ID: new_line_at_end_of_file,
|
||||
new_lines.ID: new_lines,
|
||||
trailing_spaces.ID: trailing_spaces,
|
||||
}
|
||||
|
||||
|
||||
def get(id):
|
||||
if id not in _RULES:
|
||||
raise ValueError('no such rule: "%s"' % id)
|
||||
|
||||
return _RULES[id]
|
||||
46
yamllint/rules/colons.py
Normal file
46
yamllint/rules/colons.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2016 Adrien Vergé
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import yaml
|
||||
|
||||
from yamllint.errors import LintProblem
|
||||
|
||||
|
||||
ID = 'colons'
|
||||
TYPE = 'token'
|
||||
CONF = {'max-spaces-before': int,
|
||||
'max-spaces-after': int}
|
||||
|
||||
|
||||
def check(conf, token, prev, next):
|
||||
if isinstance(token, yaml.ValueToken):
|
||||
if (prev is not None and
|
||||
prev.end_mark.line == token.start_mark.line and
|
||||
conf['max-spaces-before'] != - 1 and
|
||||
(prev.end_mark.pointer + conf['max-spaces-before'] <
|
||||
token.start_mark.pointer)):
|
||||
yield LintProblem(token.start_mark.line + 1,
|
||||
token.start_mark.column,
|
||||
'too many spaces before colon')
|
||||
|
||||
if (next is not None and
|
||||
token.end_mark.line == next.start_mark.line and
|
||||
conf['max-spaces-after'] != - 1 and
|
||||
(next.start_mark.pointer - token.end_mark.pointer >
|
||||
conf['max-spaces-after'])):
|
||||
yield LintProblem(token.start_mark.line + 1,
|
||||
next.start_mark.column,
|
||||
'too many spaces after colon')
|
||||
44
yamllint/rules/document_end.py
Normal file
44
yamllint/rules/document_end.py
Normal file
@@ -0,0 +1,44 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2016 Adrien Vergé
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import yaml
|
||||
|
||||
from yamllint.errors import LintProblem
|
||||
|
||||
|
||||
ID = 'document-end'
|
||||
TYPE = 'token'
|
||||
CONF = {'present': bool}
|
||||
|
||||
|
||||
def check(conf, token, prev, next):
|
||||
if conf['present']:
|
||||
if (isinstance(token, yaml.StreamEndToken) and
|
||||
not (isinstance(prev, yaml.DocumentEndToken) or
|
||||
isinstance(prev, yaml.StreamStartToken))):
|
||||
yield LintProblem(token.start_mark.line, 1,
|
||||
'missing document end "..."')
|
||||
elif (isinstance(token, yaml.DocumentStartToken) and
|
||||
not (isinstance(prev, yaml.DocumentEndToken) or
|
||||
isinstance(prev, yaml.StreamStartToken))):
|
||||
yield LintProblem(token.start_mark.line + 1, 1,
|
||||
'missing document end "..."')
|
||||
|
||||
else:
|
||||
if isinstance(token, yaml.DocumentEndToken):
|
||||
yield LintProblem(token.start_mark.line + 1,
|
||||
token.start_mark.column + 1,
|
||||
'found forbidden document end "..."')
|
||||
43
yamllint/rules/document_start.py
Normal file
43
yamllint/rules/document_start.py
Normal file
@@ -0,0 +1,43 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2016 Adrien Vergé
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import yaml
|
||||
|
||||
from yamllint.errors import LintProblem
|
||||
|
||||
|
||||
ID = 'document-start'
|
||||
TYPE = 'token'
|
||||
CONF = {'present': bool}
|
||||
|
||||
|
||||
# TODO: Don't fail if document contains directives such as
|
||||
# %YAML 1.2
|
||||
|
||||
def check(conf, token, prev, next):
|
||||
if conf['present']:
|
||||
if ((isinstance(prev, yaml.StreamStartToken) or
|
||||
isinstance(prev, yaml.DocumentEndToken)) and
|
||||
not (isinstance(token, yaml.DocumentStartToken) or
|
||||
isinstance(token, yaml.StreamEndToken))):
|
||||
yield LintProblem(token.start_mark.line + 1, 1,
|
||||
'missing document start "---"')
|
||||
|
||||
else:
|
||||
if isinstance(token, yaml.DocumentStartToken):
|
||||
yield LintProblem(token.start_mark.line + 1,
|
||||
token.start_mark.column + 1,
|
||||
'found forbidden document start "---"')
|
||||
59
yamllint/rules/empty_lines.py
Normal file
59
yamllint/rules/empty_lines.py
Normal file
@@ -0,0 +1,59 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2016 Adrien Vergé
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from yamllint.errors import LintProblem
|
||||
|
||||
|
||||
ID = 'empty-lines'
|
||||
TYPE = 'line'
|
||||
CONF = {'max': int,
|
||||
'max-start': int,
|
||||
'max-end': int}
|
||||
|
||||
|
||||
def check(conf, line):
|
||||
if line.start == line.end and line.end < len(line.buffer):
|
||||
# Only alert on the last blank line of a serie
|
||||
if (line.end < len(line.buffer) - 1 and
|
||||
line.buffer[line.end + 1] == '\n'):
|
||||
return
|
||||
|
||||
blank_lines = 0
|
||||
|
||||
while (line.start > blank_lines and
|
||||
line.buffer[line.start - blank_lines - 1] == '\n'):
|
||||
blank_lines += 1
|
||||
|
||||
max = conf['max']
|
||||
|
||||
# Special case: start of document
|
||||
if line.start - blank_lines == 0:
|
||||
blank_lines += 1 # first line doesn't have a preceding \n
|
||||
max = conf['max-start']
|
||||
|
||||
# Special case: end of document
|
||||
# NOTE: The last line of a file is always supposed to end with a new
|
||||
# line. See POSIX definition of a line at:
|
||||
if line.end == len(line.buffer) - 1 and line.buffer[line.end] == '\n':
|
||||
# Allow the exception of the one-byte file containing '\n'
|
||||
if line.end == 0:
|
||||
return
|
||||
|
||||
max = conf['max-end']
|
||||
|
||||
if blank_lines > max:
|
||||
yield LintProblem(line.line_no, 1, 'too many blank lines (%d > %d)'
|
||||
% (blank_lines, max))
|
||||
34
yamllint/rules/hyphens.py
Normal file
34
yamllint/rules/hyphens.py
Normal file
@@ -0,0 +1,34 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2016 Adrien Vergé
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import yaml
|
||||
|
||||
from yamllint.errors import LintProblem
|
||||
|
||||
|
||||
ID = 'hyphens'
|
||||
TYPE = 'token'
|
||||
CONF = {'max-spaces-after': int}
|
||||
|
||||
|
||||
def check(conf, token, prev, next):
|
||||
if isinstance(token, yaml.BlockEntryToken):
|
||||
if token.end_mark.line == next.start_mark.line:
|
||||
if (next.start_mark.pointer - token.end_mark.pointer >
|
||||
conf['max-spaces-after']):
|
||||
yield LintProblem(token.start_mark.line + 1,
|
||||
next.start_mark.column,
|
||||
'too many spaces after hyphen')
|
||||
63
yamllint/rules/indentation.py
Normal file
63
yamllint/rules/indentation.py
Normal file
@@ -0,0 +1,63 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2016 Adrien Vergé
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import yaml
|
||||
|
||||
from yamllint.errors import LintProblem
|
||||
|
||||
|
||||
ID = 'indentation'
|
||||
TYPE = 'token'
|
||||
CONF = {'spaces': int}
|
||||
|
||||
|
||||
def check(conf, token, prev, next):
|
||||
if isinstance(token, yaml.StreamEndToken):
|
||||
return
|
||||
|
||||
if (prev is None or isinstance(prev, yaml.StreamStartToken) or
|
||||
isinstance(prev, yaml.DirectiveToken) or
|
||||
isinstance(prev, yaml.DocumentStartToken)):
|
||||
if token.start_mark.column != 0:
|
||||
yield LintProblem(
|
||||
token.end_mark.line + 1, token.start_mark.column + 1,
|
||||
'found indentation of %d instead of %d' %
|
||||
(token.start_mark.column, 0))
|
||||
return
|
||||
|
||||
if token.start_mark.line > prev.end_mark.line:
|
||||
buffer = prev.end_mark.buffer
|
||||
|
||||
start = buffer.rfind('\n', 0, prev.end_mark.pointer) + 1
|
||||
prev_indent = 0
|
||||
|
||||
# YAML recognizes two white space characters: space and tab.
|
||||
# http://yaml.org/spec/1.2/spec.html#id2775170
|
||||
while buffer[start + prev_indent] in ' \t':
|
||||
prev_indent += 1
|
||||
|
||||
# Discard any leading '- '
|
||||
if (buffer[start + prev_indent:start + prev_indent + 2] == '- '):
|
||||
prev_indent += 2
|
||||
while buffer[start + prev_indent] in ' \t':
|
||||
prev_indent += 1
|
||||
|
||||
if (token.start_mark.column > prev_indent and
|
||||
token.start_mark.column != prev_indent + conf['spaces']):
|
||||
yield LintProblem(
|
||||
token.end_mark.line + 1, token.start_mark.column + 1,
|
||||
'found indentation of %d instead of %d' %
|
||||
(token.start_mark.column, prev_indent + conf['spaces']))
|
||||
29
yamllint/rules/line_length.py
Normal file
29
yamllint/rules/line_length.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2016 Adrien Vergé
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from yamllint.errors import LintProblem
|
||||
|
||||
|
||||
ID = 'line-length'
|
||||
TYPE = 'line'
|
||||
CONF = {'max': int}
|
||||
|
||||
|
||||
def check(conf, line):
|
||||
if line.end - line.start > conf['max']:
|
||||
yield LintProblem(line.line_no, conf['max'] + 1,
|
||||
'line too long (%d > %d characters)' %
|
||||
(line.end - line.start, conf['max']))
|
||||
27
yamllint/rules/new_line_at_end_of_file.py
Normal file
27
yamllint/rules/new_line_at_end_of_file.py
Normal file
@@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2016 Adrien Vergé
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from yamllint.errors import LintProblem
|
||||
|
||||
|
||||
ID = 'new-line-at-end-of-file'
|
||||
TYPE = 'line'
|
||||
|
||||
|
||||
def check(conf, line):
|
||||
if line.end == len(line.buffer) and line.end > line.start:
|
||||
yield LintProblem(line.line_no, line.end - line.start + 1,
|
||||
'no new line character at the end of file')
|
||||
34
yamllint/rules/new_lines.py
Normal file
34
yamllint/rules/new_lines.py
Normal file
@@ -0,0 +1,34 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2016 Adrien Vergé
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from yamllint.errors import LintProblem
|
||||
|
||||
|
||||
ID = 'new-lines'
|
||||
TYPE = 'line'
|
||||
CONF = {'type': str}
|
||||
|
||||
|
||||
def check(conf, line):
|
||||
if line.start == 0 and len(line.buffer) > line.end:
|
||||
if conf['type'] == 'dos':
|
||||
if line.buffer[line.end - 1:line.end + 1] != '\r\n':
|
||||
yield LintProblem(1, line.end - line.start + 1,
|
||||
'wrong new line character: expected \\r\\n')
|
||||
else:
|
||||
if line.end > 0 and line.buffer[line.end - 1] == '\r':
|
||||
yield LintProblem(1, line.end - line.start,
|
||||
'wrong new line character: expected \\n')
|
||||
39
yamllint/rules/trailing_spaces.py
Normal file
39
yamllint/rules/trailing_spaces.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2016 Adrien Vergé
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import string
|
||||
|
||||
from yamllint.errors import LintProblem
|
||||
|
||||
|
||||
ID = 'trailing-spaces'
|
||||
TYPE = 'line'
|
||||
|
||||
|
||||
def check(conf, line):
|
||||
if line.end == 0:
|
||||
return
|
||||
|
||||
# YAML recognizes two white space characters: space and tab.
|
||||
# http://yaml.org/spec/1.2/spec.html#id2775170
|
||||
|
||||
pos = line.end
|
||||
while line.buffer[pos - 1] in string.whitespace and pos > line.start:
|
||||
pos -= 1
|
||||
|
||||
if pos != line.end and line.buffer[pos] in ' \t':
|
||||
yield LintProblem(line.line_no, pos - line.start + 1,
|
||||
'trailing spaces')
|
||||
Reference in New Issue
Block a user