Permalink
Browse files

MarkdownBear: Add `remark-lint` settings

Closes #926
  • Loading branch information...
yash-nisar committed Jul 21, 2017
1 parent 4d03ff3 commit 3dc08bfceb4d2e91bb8b198bdaa63d3fde06566b
Showing with 301 additions and 6 deletions.
  1. +161 −6 bears/markdown/MarkdownBear.py
  2. +140 −0 tests/markdown/MarkdownBearTest.py
@@ -66,7 +66,27 @@ def create_arguments(filename, file, config_file,
horizontal_rule_spaces: bool=False,
horizontal_rule_repeat: int=3,
max_line_length: int=None,
check_links: bool=False):
check_links: bool=False,
blockquote_indentation: int=2,
enforce_checkbox_content_indentation: bool=True,
code_block_style: str='consistent',
enforce_labels_at_eof: bool=True,
first_heading_level: int=None,
enforce_heading_level_increment: bool=False,
max_heading_length: int=60,
prohibit_duplicate_definitions: bool=True,
prohibit_duplicate_headings_in_section: bool=True,
prohibit_duplicate_headings: bool=True,
prohibit_empty_url: bool=True,
prohibit_irregular_chars_filename:
str='\\.a-zA-Z0-9-_',
prohibit_punctuations_in_heading: str='.,;:!?',
prohibit_html: bool=True,
prohibit_shortcut_reference_image: bool=True,
prohibit_shortcut_reference_link: bool=True,
use_spaces: bool=True,
check_undefined_references: bool=True,
check_unused_definition: bool=True):
"""
:param bullets:
Character to use for bullets in lists. Can be "-", "*" or "+".
@@ -111,6 +131,121 @@ def create_arguments(filename, file, config_file,
The maximum line length allowed.
:param check_links:
Checks if links to headings and files in markdown are valid.
:param blockquote_indentation:
Warn when blockquotes are either indented too much or too little.
:param enforce_checkbox_content_indentation:
Warn when list item checkboxes are followed by unnecessary
whitespace.
:param code_block_style:
Warn when code-blocks do not adhere to a given style. Can be
``consistent``, ``fenced``, or ``indented``. The default value,
``consistent``, detects the first used code-block style, and will
warn when a subsequent code-block uses a different style.
:param enforce_labels_at_eof:
Warn when definitions are not placed at the end of the file.
For example: If set to ``True``, this will throw a warning::
Paragraph.
[example]: http://example.com "Example Domain"
Another paragraph.
:param first_heading_level:
Warn when the first heading has a level other than a specified
value.
For example: If set to ``2``, this will throw a warning::
# Bravo
Paragraph.
:param enforce_heading_level_increment:
Warn when headings increment with more than 1 level at a time.
For example: If set to ``True``, prefer this::
# Alpha
## Bravo
over this::
# Alpha
### Bravo
:param max_heading_length:
The maximum heading length allowed. Ignores markdown syntax, only
checks the plain text content.
:param prohibit_duplicate_definitions:
Warn when duplicate definitions are found.
For example: If set to ``True``, this will throw a warning::
[foo]: bar
[foo]: qux
:param prohibit_duplicate_headings_in_section:
Warn when duplicate headings are found, but only when on the same
level, “in” the same section.
For example: If set to ``True``, this will throw a warning::
## Foxtrot
### Golf
### Golf
:param prohibit_duplicate_headings:
Warn when duplicate headings are found.
For example: If set to ``True``, this will throw a warning::
# Foo
## Foo
## [Foo](http://foo.com/bar)
:param prohibit_empty_url:
Warn for empty URLs in links and images.
For example: If set to ``True``, this will throw a warning::
[golf]().
![hotel]().
:param prohibit_irregular_chars_filename:
Warn when file names contain irregular characters: characters other
than alpha-numericals, dashes, dots (full-stops) and underscores.
Can take ``RegExp`` or ``string``. Any match by the given
expression triggers a warning.
:param prohibit_punctuations_in_heading:
Warn when a heading ends with a group of characters. Can take a
``string`` that contains the group of characters.
:param prohibit_html:
Warn when HTML elements are used. Ignores comments, because they
are used remark, because markdown doesn’t have native comments.
For example: If set to ``True``, this will throw a warning::
<h1>Hello</h1>
:param prohibit_shortcut_reference_image:
Warn when shortcut reference images are used.
For example: If set to ``True``, this will throw a warning::
![foo]
[foo]: http://foo.bar/baz.png
:param prohibit_shortcut_reference_link:
Warn when shortcut reference links are used.
For example: If set to ``True``, this will throw a warning::
[foo]
[foo]: http://foo.bar/baz
:param use_spaces:
Warn when tabs are used instead of spaces.
:param check_undefined_references:
Warn when references to undefined definitions are found.
For example: If set to ``True``, this will throw a warning::
[bar][]
:param check_unused_definition:
Warn when unused definitions are found.
For example: If set to ``True``, this will throw a warning::
[bar]: https://example.com
"""
remark_configs = {
'bullet': bullets, # - or *
@@ -130,7 +265,28 @@ def create_arguments(filename, file, config_file,
'ruleSpaces': horizontal_rule_spaces, # Bool
'ruleRepetition': horizontal_rule_repeat, # int
}
remark_lint_configs = {}
remark_lint_configs = {
'blockquoteIndentation': blockquote_indentation,
'checkboxContentIndent': enforce_checkbox_content_indentation,
'codeBlockStyle': code_block_style,
'finalDefinition': enforce_labels_at_eof,
'firstHeadingLevel': first_heading_level,
'headingIncrement': enforce_heading_level_increment,
'maximumHeadingLength': max_heading_length,
'noDuplicateDefinitions': prohibit_duplicate_definitions,
'noDuplicateHeadingsInSection':
prohibit_duplicate_headings_in_section,
'noDuplicateHeadings': prohibit_duplicate_headings,
'noEmptyURL': prohibit_empty_url,
'noFileNameIrregularCharacters': prohibit_irregular_chars_filename,
'noHeadingPunctuation': prohibit_punctuations_in_heading,
'noHTML': prohibit_html,
'noShortcutReferenceImage': prohibit_shortcut_reference_image,
'noShortcutReferenceLink': prohibit_shortcut_reference_link,
'noTabs': use_spaces,
'noUndefinedReferences': check_undefined_references,
'noUnusedDefinitions': check_unused_definition,
}
if max_line_length:
remark_lint_configs['maximumLineLength'] = max_line_length
@@ -141,10 +297,9 @@ def create_arguments(filename, file, config_file,
args = [filename, '--no-color', '--quiet', '--setting', settings]
if remark_lint_configs:
config_json = json.dumps(remark_lint_configs)
lint = 'lint=' + config_json[1:-1]
args += ['--use', lint]
config_json = json.dumps(remark_lint_configs)
lint = 'lint=' + config_json[1:-1]
args += ['--use', lint]
if check_links:
args += ['--use', 'validate-links']
@@ -33,6 +33,55 @@
Read more [This link exists](#world).
"""
blockquote_indentation_file = """> Hello
Paragraph.
"""
checkbox_content_indentation_file = """Some line.
- [x] List item
"""
labels_at_eof_unused_definition_file = """Paragraph.
[example]: http://example.com "Example Domain"
Another paragraph.
"""
first_heading_level_file = """# Bravo
Paragraph.
"""
heading_level_increment_file = """# Charlie
### Delta
"""
empty_url_file = """[golf](<>).
![hotel](<>).
"""
duplicate_heading_file = """## Foxtrot
### Golf
### Golf
"""
punctuation_in_heading_file = """# Hello:
# Hello?
# Hello!
"""
html_file = """<h1>Hello</h1>
"""
MarkdownBearTest = verify_local_bear(MarkdownBear,
valid_files=(test_file2,),
invalid_files=(test_file1,))
@@ -81,3 +130,94 @@ def test_valid_link(self):
with prepare_file(content, None) as (file, fname):
with execute_bear(self.uut, fname, file) as results:
self.assertEqual(results, [])
def test_blockquote_indentation(self):
content = blockquote_indentation_file.splitlines()
with prepare_file(content, None) as (file, fname):
with execute_bear(self.uut, fname, file) as results:
self.assertEqual(results[0].message,
'Remove 1 space between blockquote and '
'content')
self.assertEqual(results[0].severity, RESULT_SEVERITY.NORMAL)
def test_checkbox_content_indentation(self):
content = checkbox_content_indentation_file.splitlines()
with prepare_file(content, None) as (file, fname):
with execute_bear(self.uut, fname, file) as results:
self.assertEqual(results[0].message,
'Checkboxes should be followed by a single '
'character')
self.assertEqual(results[0].severity, RESULT_SEVERITY.NORMAL)
def test_codeblock_style_unused_definition(self):
content = labels_at_eof_unused_definition_file.splitlines()
with prepare_file(content, None) as (file, fname):
with execute_bear(self.uut, fname, file) as results:
self.assertEqual(results[0].message,
'Move definitions to the end of the file '
'(after the node at line `5`)')
self.assertEqual(results[0].severity, RESULT_SEVERITY.NORMAL)
self.assertEqual(results[1].message,
'Found unused definition')
self.assertEqual(results[1].severity, RESULT_SEVERITY.NORMAL)
def test_first_heading_level(self):
content = first_heading_level_file.splitlines()
self.section.append(Setting('first_heading_level', 2))
with prepare_file(content, None) as (file, fname):
with execute_bear(self.uut, fname, file) as results:
self.assertEqual(results[0].message,
'First heading level should be `2`')
self.assertEqual(results[0].severity, RESULT_SEVERITY.NORMAL)
def test_heading_level_increment(self):
content = heading_level_increment_file.splitlines()
self.section.append(Setting('enforce_heading_level_increment', True))
with prepare_file(content, None) as (file, fname):
with execute_bear(self.uut, fname, file) as results:
self.assertEqual(results[0].message,
'Heading levels should increment by one '
'level at a time')
self.assertEqual(results[0].severity, RESULT_SEVERITY.NORMAL)
def test_empty_url(self):
content = empty_url_file.splitlines()
with prepare_file(content, None) as (file, fname):
with execute_bear(self.uut, fname, file) as results:
self.assertEqual(results[0].message,
'Don’t use links without URL')
self.assertEqual(results[0].severity, RESULT_SEVERITY.NORMAL)
self.assertEqual(results[1].message,
'Don’t use images without URL')
self.assertEqual(results[1].severity, RESULT_SEVERITY.NORMAL)
def test_duplicate_headings(self):
content = duplicate_heading_file.splitlines()
with prepare_file(content, None) as (file, fname):
with execute_bear(self.uut, fname, file) as results:
self.assertEqual(results[0].message,
'Do not use headings with similar content '
'per section (3:1)')
self.assertEqual(results[0].severity, RESULT_SEVERITY.NORMAL)
def test_punctuations_in_heading(self):
content = punctuation_in_heading_file.splitlines()
with prepare_file(content, None) as (file, fname):
with execute_bear(self.uut, fname, file) as results:
self.assertEqual(results[0].message,
'Don’t add a trailing `:` to headings')
self.assertEqual(results[0].severity, RESULT_SEVERITY.NORMAL)
self.assertEqual(results[1].message,
'Don’t add a trailing `?` to headings')
self.assertEqual(results[1].severity, RESULT_SEVERITY.NORMAL)
self.assertEqual(results[2].message,
'Don’t add a trailing `!` to headings')
self.assertEqual(results[2].severity, RESULT_SEVERITY.NORMAL)
def test_html_in_markdown(self):
content = html_file.splitlines()
with prepare_file(content, None) as (file, fname):
with execute_bear(self.uut, fname, file) as results:
self.assertEqual(results[0].message,
'Do not use HTML in markdown')
self.assertEqual(results[0].severity, RESULT_SEVERITY.NORMAL)

0 comments on commit 3dc08bf

Please sign in to comment.