Initial commit

This commit is contained in:
Adrien Vergé
2016-01-09 11:53:44 +01:00
commit 350213b165
36 changed files with 2738 additions and 0 deletions

80
yamllint/__init__.py Normal file
View 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
View 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
View 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
View 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
View 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
View 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)

View 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
View 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')

View 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 "..."')

View 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 "---"')

View 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
View 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')

View 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']))

View 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']))

View 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')

View 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')

View 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')