Skip to content

Commit

Permalink
bears/stylus: Add StylintBear
Browse files Browse the repository at this point in the history
Closes #754
  • Loading branch information
yash-nisar committed Jun 2, 2017
1 parent 95b85f5 commit 09a1197
Show file tree
Hide file tree
Showing 15 changed files with 244 additions and 0 deletions.
46 changes: 46 additions & 0 deletions bears/stylus/StylintBear.py
@@ -0,0 +1,46 @@
from coalib.bearlib.abstractions.Linter import linter
from dependency_management.requirements.NpmRequirement import NpmRequirement


@linter(executable='stylint',
output_format='regex',
output_regex=r'(?P<line>\d+):?(?P<column>\d+)?\s+.*?'
r'(?P<severity>error|warning)\s+(?P<message>.+)')
class StylintBear:
"""
Attempts to catch little mistakes (duplication of rules for instance) and
enforces a code style guide on Stylus (a dynamic stylesheet language
with the ``.styl`` extension that is compiled into CSS) files.
The ``StylintBear`` is able to catch following problems:
- Duplication of rules
- Mixed spaces and tabs
- Unnecessary brackets
- Missing colon between property and value
- Naming conventions
- Trailing whitespace
- Consistent quotation style
- Use of extra spaces inside parenthesis
- Naming convention when declaring classes, ids, and variables
- Unnecessary leading zeroes on decimal points
- Checks if a property is valid CSS or HTML
"""

LANGUAGES = {'Stylus'}
REQUIREMENTS = {NpmRequirement('stylint', '1.5.9')}
AUTHORS = {'The coala developers'}
AUTHORS_EMAILS = {'coala-devel@googlegroups.com'}
LICENSE = 'AGPL-3.0'
CAN_DETECT = {'Formatting', 'Syntax', 'Redundancy'}
SEE_MORE = 'https://github.com/SimenB/stylint'

@staticmethod
def create_arguments(filename, file, config_file, stylint_config: str=''):
"""
:param stylint_config:
The location of the ``.stylintrc`` config file.
"""
if stylint_config:
return '--config', stylint_config, filename
else:
return filename,
Empty file added bears/stylus/__init__.py
Empty file.
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -20,6 +20,7 @@
"remark-cli": "~2",
"remark-lint": "~5",
"stylelint": "~7",
"stylint": "~1.5.9",
"tslint": "~3",
"typescript": ">=1.7.3",
"write-good": "~0.9.1"
Expand Down
158 changes: 158 additions & 0 deletions tests/stylus/StylintBearTest.py
@@ -0,0 +1,158 @@
import os
from queue import Queue

from bears.stylus.StylintBear import StylintBear
from coalib.results.Result import Result
from coalib.results.RESULT_SEVERITY import RESULT_SEVERITY
from coalib.settings.Section import Section
from coalib.testing.BearTestHelper import generate_skip_decorator
from coalib.testing.LocalBearTestHelper import LocalBearTestHelper


def get_testfile_path(name):
return os.path.join(os.path.dirname(__file__),
'stylint_test_files',
name)


def load_testfile(name):
with open(get_testfile_path(name)) as f:
return f.readlines()


@generate_skip_decorator(StylintBear)
class StylintBearTest(LocalBearTestHelper):

def setUp(self):
self.uut = StylintBear(Section('name'), Queue())

def test_bad_missing_colon(self):
filename = 'test_bad_missing_colon.styl'
file_contents = load_testfile(filename)
self.check_results(
self.uut,
file_contents,
[Result.from_values('StylintBear',
message='missing colon between property '
'and value colons',
file=get_testfile_path(filename),
line=2,
column=6,
severity=RESULT_SEVERITY.NORMAL)],
filename=get_testfile_path(filename))

def test_bad_duplicates(self):
filename = 'test_bad_duplicates.styl'
file_contents = load_testfile(filename)
self.check_results(
self.uut,
file_contents,
[Result.from_values('StylintBear',
message='duplicate property or selector, '
'consider merging duplicates',
file=get_testfile_path(filename),
line=4,
severity=RESULT_SEVERITY.NORMAL)],
filename=get_testfile_path(filename))

def test_bad_no_important(self):
filename = 'test_bad_no_important.styl'
file_contents = load_testfile(filename)
self.check_results(
self.uut,
file_contents,
[Result.from_values('StylintBear',
message='!important is disallowed '
'noImportant',
file=get_testfile_path(filename),
line=2,
column=9,
severity=RESULT_SEVERITY.NORMAL)],
filename=get_testfile_path(filename))

def test_bad_brackets(self):
filename = 'test_bad_brackets.styl'
file_contents = load_testfile(filename)
self.check_results(
self.uut,
file_contents,
[Result.from_values('StylintBear',
message='unnecessary bracket brackets',
file=get_testfile_path(filename),
line=1,
column=13,
severity=RESULT_SEVERITY.NORMAL),
Result.from_values('StylintBear',
message='unnecessary bracket brackets',
file=get_testfile_path(filename),
line=3,
severity=RESULT_SEVERITY.NORMAL)],
filename=get_testfile_path(filename))

def test_bad_semicolon(self):
filename = 'test_bad_semicolon.styl'
file_contents = load_testfile(filename)
self.check_results(
self.uut,
file_contents,
[Result.from_values('StylintBear',
message='unnecessary semicolon found '
'semicolons',
file=get_testfile_path(filename),
line=2,
column=19,
severity=RESULT_SEVERITY.NORMAL)],
filename=get_testfile_path(filename))

def test_bad_alphabetical_order(self):
filename = 'test_bad_alphabetical_order.styl'
file_contents = load_testfile(filename)
self.check_results(
self.uut,
file_contents,
[Result.from_values('StylintBear',
message='prefer alphabetical when sorting '
'properties sortOrder',
file=get_testfile_path(filename),
line=3,
severity=RESULT_SEVERITY.NORMAL)],
filename=get_testfile_path(filename))

def test_bad_trailing_whitespace(self):
filename = 'test_bad_trailing_whitespace.styl'
file_contents = load_testfile(filename)
self.check_results(
self.uut,
file_contents,
[Result.from_values('StylintBear',
message='trailing whitespace '
'trailingWhitespace',
file=get_testfile_path(filename),
line=3,
column=22,
severity=RESULT_SEVERITY.NORMAL)],
filename=get_testfile_path(filename))

def test_bad_mixed_spaces_tabs(self):
filename = 'test_bad_mixed_spaces_tabs.styl'
file_contents = load_testfile(filename)
self.check_results(
self.uut,
file_contents,
[Result.from_values('StylintBear',
message='mixed spaces and tabs',
file=get_testfile_path(filename),
line=3,
column=0,
severity=RESULT_SEVERITY.NORMAL)],
filename=get_testfile_path(filename),
settings={'stylint_config': get_testfile_path('.stylintrc')})

def test_valid_file(self):
filename = 'test_valid_file.styl'
file_contents = load_testfile(filename)
self.check_results(
self.uut,
file_contents,
[],
filename=get_testfile_path(filename))
Empty file added tests/stylus/__init__.py
Empty file.
5 changes: 5 additions & 0 deletions tests/stylus/stylint_test_files/.stylintrc
@@ -0,0 +1,5 @@
{
"depthLimit": 4,
"indentPref": 4,
"mixed": true
}
@@ -0,0 +1,3 @@
.bankTitle
padding-right: 2em
font-weight: bold
3 changes: 3 additions & 0 deletions tests/stylus/stylint_test_files/test_bad_brackets.styl
@@ -0,0 +1,3 @@
.pageContent {
padding: 1em
}
5 changes: 5 additions & 0 deletions tests/stylus/stylint_test_files/test_bad_duplicates.styl
@@ -0,0 +1,5 @@
test = @block
margin: 0

test =
margin: auto
2 changes: 2 additions & 0 deletions tests/stylus/stylint_test_files/test_bad_missing_colon.styl
@@ -0,0 +1,2 @@
test = @block
margin 0
@@ -0,0 +1,3 @@
test = @block
margin: 0
padding-right: 2em
2 changes: 2 additions & 0 deletions tests/stylus/stylint_test_files/test_bad_no_important.styl
@@ -0,0 +1,2 @@
.im-important
margin 0 !important
3 changes: 3 additions & 0 deletions tests/stylus/stylint_test_files/test_bad_semicolon.styl
@@ -0,0 +1,3 @@
.bankTitle
font-weight: bold;
padding-right: 2em
@@ -0,0 +1,3 @@
.bankTitle
font-weight: bold
padding-right: 2em
10 changes: 10 additions & 0 deletions tests/stylus/stylint_test_files/test_valid_file.styl
@@ -0,0 +1,10 @@
border-radius()
-moz-border-radius: arguments
-webkit-border-radius: arguments
border-radius: arguments

body
font: 12px Helvetica, Arial, sans-serif

a.button
border-radius: 5px

0 comments on commit 09a1197

Please sign in to comment.