Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MarkdownBear: Add remark-lint settings #1942

Merged
merged 1 commit into from
Jul 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 161 additions & 6 deletions bears/markdown/MarkdownBear.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 "+".
Expand Down Expand Up @@ -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 *
Expand All @@ -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
Expand All @@ -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']
Expand Down
140 changes: 140 additions & 0 deletions tests/markdown/MarkdownBearTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,))
Expand Down Expand Up @@ -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)