Rules: Add the 'comments' rule
							parent
							
								
									5c4c208b98
								
							
						
					
					
						commit
						851b9ac42c
					
				| @ -0,0 +1,165 @@ | |||||||
|  | # -*- 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 tests.rules.common import RuleTestCase | ||||||
|  | from yamllint.rules.inline_comments import (Comment, | ||||||
|  |                                             get_comments_until_next_token) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class CommentsTestCase(RuleTestCase): | ||||||
|  |     rule_id = 'comments' | ||||||
|  | 
 | ||||||
|  |     def check_comments(self, buffer, *expected): | ||||||
|  |         yaml_loader = yaml.BaseLoader(buffer) | ||||||
|  | 
 | ||||||
|  |         comments = [] | ||||||
|  | 
 | ||||||
|  |         next = yaml_loader.peek_token() | ||||||
|  |         while next is not None: | ||||||
|  |             curr = yaml_loader.get_token() | ||||||
|  |             next = yaml_loader.peek_token() | ||||||
|  |             for comment in get_comments_until_next_token(curr, next): | ||||||
|  |                 comments.append(comment) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(comments, list(expected)) | ||||||
|  | 
 | ||||||
|  |     def test_get_comments_until_next_token(self): | ||||||
|  |         self.check_comments('# comment\n', | ||||||
|  |                             Comment(1, 1, '# comment', 0)) | ||||||
|  |         self.check_comments('---\n' | ||||||
|  |                             '# comment\n' | ||||||
|  |                             '...\n', | ||||||
|  |                             Comment(2, 1, '# comment', 0)) | ||||||
|  |         self.check_comments('---\n' | ||||||
|  |                             '# no newline char', | ||||||
|  |                             Comment(2, 1, '# no newline char', 0)) | ||||||
|  |         self.check_comments('\n' | ||||||
|  |                             '   # indented comment\n', | ||||||
|  |                             Comment(2, 4, '# indented comment', 0)) | ||||||
|  |         self.check_comments('\n' | ||||||
|  |                             '# trailing spaces    \n', | ||||||
|  |                             Comment(2, 1, '# trailing spaces    ', 0)) | ||||||
|  |         self.check_comments('# comment one\n' | ||||||
|  |                             '\n' | ||||||
|  |                             'key: val  # key=val\n' | ||||||
|  |                             '\n' | ||||||
|  |                             '# this is\n' | ||||||
|  |                             '# a block     \n' | ||||||
|  |                             '# comment\n' | ||||||
|  |                             '\n' | ||||||
|  |                             'other:\n' | ||||||
|  |                             '  - foo  # equals\n' | ||||||
|  |                             '         # bar\n', | ||||||
|  |                             Comment(1, 1, '# comment one', 0), | ||||||
|  |                             Comment(3, 11, '# key=val', 0), | ||||||
|  |                             Comment(5, 1, '# this is', 0), | ||||||
|  |                             Comment(6, 1, '# a block     ', 0), | ||||||
|  |                             Comment(7, 1, '# comment', 0), | ||||||
|  |                             Comment(10, 10, '# equals', 0), | ||||||
|  |                             Comment(11, 10, '# bar', 0)) | ||||||
|  | 
 | ||||||
|  |     def test_disabled(self): | ||||||
|  |         conf = 'comments: disable' | ||||||
|  |         self.check('---\n' | ||||||
|  |                    '#comment\n' | ||||||
|  |                    '\n' | ||||||
|  |                    'test: #    description\n' | ||||||
|  |                    '  - foo  # bar\n' | ||||||
|  |                    '  - hello #world\n' | ||||||
|  |                    '\n' | ||||||
|  |                    '# comment 2\n' | ||||||
|  |                    '#comment 3\n' | ||||||
|  |                    '  #comment 3 bis\n' | ||||||
|  |                    '  #  comment 3 ter\n' | ||||||
|  |                    '\n' | ||||||
|  |                    'string: "Une longue phrase." # this is French\n', conf) | ||||||
|  | 
 | ||||||
|  |     def test_starting_space(self): | ||||||
|  |         conf = ('comments:\n' | ||||||
|  |                 '  require-starting-space: yes\n' | ||||||
|  |                 '  min-spaces-from-content: -1\n') | ||||||
|  |         self.check('---\n' | ||||||
|  |                    '# comment\n' | ||||||
|  |                    '\n' | ||||||
|  |                    'test:  #     description\n' | ||||||
|  |                    '  - foo  #   bar\n' | ||||||
|  |                    '  - hello  # world\n' | ||||||
|  |                    '\n' | ||||||
|  |                    '# comment 2\n' | ||||||
|  |                    '# comment 3\n' | ||||||
|  |                    '  #  comment 3 bis\n' | ||||||
|  |                    '  #  comment 3 ter\n', conf) | ||||||
|  |         self.check('---\n' | ||||||
|  |                    '#comment\n' | ||||||
|  |                    '\n' | ||||||
|  |                    'test:  #    description\n' | ||||||
|  |                    '  - foo  #  bar\n' | ||||||
|  |                    '  - hello  #world\n' | ||||||
|  |                    '\n' | ||||||
|  |                    '# comment 2\n' | ||||||
|  |                    '#comment 3\n' | ||||||
|  |                    '  #comment 3 bis\n' | ||||||
|  |                    '  #  comment 3 ter\n', conf, | ||||||
|  |                    problem1=(2, 2), problem2=(6, 13), | ||||||
|  |                    problem4=(9, 2), problem5=(10, 4)) | ||||||
|  | 
 | ||||||
|  |     def test_spaces_from_content(self): | ||||||
|  |         conf = ('comments:\n' | ||||||
|  |                 '  require-starting-space: no\n' | ||||||
|  |                 '  min-spaces-from-content: 2\n') | ||||||
|  |         self.check('---\n' | ||||||
|  |                    '# comment\n' | ||||||
|  |                    '\n' | ||||||
|  |                    'test:  #    description\n' | ||||||
|  |                    '  - foo  #  bar\n' | ||||||
|  |                    '  - hello  #world\n' | ||||||
|  |                    '\n' | ||||||
|  |                    'string: "Une longue phrase."  # this is French\n', conf) | ||||||
|  |         self.check('---\n' | ||||||
|  |                    '# comment\n' | ||||||
|  |                    '\n' | ||||||
|  |                    'test: #    description\n' | ||||||
|  |                    '  - foo  # bar\n' | ||||||
|  |                    '  - hello #world\n' | ||||||
|  |                    '\n' | ||||||
|  |                    'string: "Une longue phrase." # this is French\n', conf, | ||||||
|  |                    problem1=(4, 7), problem2=(6, 11), problem3=(8, 30)) | ||||||
|  | 
 | ||||||
|  |     def test_both(self): | ||||||
|  |         conf = ('comments:\n' | ||||||
|  |                 '  require-starting-space: yes\n' | ||||||
|  |                 '  min-spaces-from-content: 2\n') | ||||||
|  |         self.check('---\n' | ||||||
|  |                    '#comment\n' | ||||||
|  |                    '\n' | ||||||
|  |                    'test: #    description\n' | ||||||
|  |                    '  - foo  # bar\n' | ||||||
|  |                    '  - hello #world\n' | ||||||
|  |                    '\n' | ||||||
|  |                    '# comment 2\n' | ||||||
|  |                    '#comment 3\n' | ||||||
|  |                    '  #comment 3 bis\n' | ||||||
|  |                    '  #  comment 3 ter\n' | ||||||
|  |                    '\n' | ||||||
|  |                    'string: "Une longue phrase." # this is French\n', conf, | ||||||
|  |                    problem1=(2, 2), | ||||||
|  |                    problem2=(4, 7), | ||||||
|  |                    problem3=(6, 11), problem4=(6, 12), | ||||||
|  |                    problem5=(9, 2), | ||||||
|  |                    problem6=(10, 4), | ||||||
|  |                    problem7=(13, 30)) | ||||||
| @ -0,0 +1,84 @@ | |||||||
|  | # -*- 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 = 'comments' | ||||||
|  | TYPE = 'token' | ||||||
|  | CONF = {'require-starting-space': bool, | ||||||
|  |         'min-spaces-from-content': int} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Comment(object): | ||||||
|  |     def __init__(self, line, column, buffer, pointer): | ||||||
|  |         self.line = line | ||||||
|  |         self.column = column | ||||||
|  |         self.buffer = buffer | ||||||
|  |         self.pointer = pointer | ||||||
|  | 
 | ||||||
|  |     def __repr__(self): | ||||||
|  |         end = self.buffer.find('\n', self.pointer) | ||||||
|  |         if end == -1: | ||||||
|  |             end = self.buffer.find('\0', self.pointer) | ||||||
|  |         if end != -1: | ||||||
|  |             return self.buffer[self.pointer:end] | ||||||
|  |         return self.buffer[self.pointer:] | ||||||
|  | 
 | ||||||
|  |     def __eq__(self, other): | ||||||
|  |         return (self.line == other.line and | ||||||
|  |                 self.column == other.column and | ||||||
|  |                 str(self) == str(other)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_comments_until_next_token(token, next): | ||||||
|  |     if next is None: | ||||||
|  |         buf = token.end_mark.buffer[token.end_mark.pointer:] | ||||||
|  |     elif token.end_mark.line == next.start_mark.line: | ||||||
|  |         return | ||||||
|  |     else: | ||||||
|  |         buf = token.end_mark.buffer[token.end_mark.pointer: | ||||||
|  |                                     next.start_mark.pointer] | ||||||
|  | 
 | ||||||
|  |     line_no = token.end_mark.line + 1 | ||||||
|  |     column_no = token.end_mark.column + 1 | ||||||
|  |     pointer = token.end_mark.pointer | ||||||
|  | 
 | ||||||
|  |     for line in buf.split('\n'): | ||||||
|  |         pos = line.find('#') | ||||||
|  |         if pos != -1: | ||||||
|  |             yield Comment(line_no, column_no + pos, | ||||||
|  |                           token.end_mark.buffer, pointer + pos) | ||||||
|  | 
 | ||||||
|  |         pointer += len(line) + 1 | ||||||
|  |         line_no += 1 | ||||||
|  |         column_no = 1 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def check(conf, token, prev, next): | ||||||
|  |     for comment in get_comments_until_next_token(token, next): | ||||||
|  |         if (conf['min-spaces-from-content'] != -1 and | ||||||
|  |                 comment.line == token.end_mark.line + 1 and | ||||||
|  |                 comment.pointer - token.end_mark.pointer < | ||||||
|  |                 conf['min-spaces-from-content']): | ||||||
|  |             yield LintProblem(comment.line, comment.column, | ||||||
|  |                               'too few spaces before comment') | ||||||
|  | 
 | ||||||
|  |         if (conf['require-starting-space'] and | ||||||
|  |                 comment.pointer + 1 < len(comment.buffer) and | ||||||
|  |                 comment.buffer[comment.pointer + 1] != ' '): | ||||||
|  |             yield LintProblem(comment.line, comment.column + 1, | ||||||
|  |                               'missing starting space in comment') | ||||||
					Loading…
					
					
				
		Reference in New Issue