Skip to content

Commit 47d3956

Browse files
committed
bears/stylus: Add StylintBear
Closes #754
1 parent 2d8e839 commit 47d3956

15 files changed

+242
-0
lines changed

Diff for: bears/stylus/StylintBear.py

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from coalib.bearlib.abstractions.Linter import linter
2+
from dependency_management.requirements.NpmRequirement import NpmRequirement
3+
4+
5+
@linter(executable='stylint',
6+
output_format='regex',
7+
output_regex=r'(?P<line>\d+):?(?P<column>\d+)?\s+.*?'
8+
r'(?P<severity>error|warning)\s+(?P<message>.+?)'
9+
r'(?: .*|\n|$)')
10+
class StylintBear:
11+
"""
12+
Attempts to catch little mistakes (duplication of rules for instance) and
13+
enforces a code style guide on Stylus (a dynamic stylesheet language
14+
with the ``.styl`` extension that is compiled into CSS) files.
15+
16+
The ``StylintBear`` is able to catch following problems:
17+
- Duplication of rules
18+
- Mixed spaces and tabs
19+
- Unnecessary brackets
20+
- Missing colon between property and value
21+
- Naming conventions
22+
- Trailing whitespace
23+
- Consistent quotation style
24+
- Use of extra spaces inside parenthesis
25+
- Naming convention when declaring classes, ids, and variables
26+
- Unnecessary leading zeroes on decimal points
27+
- Checks if a property is valid CSS or HTML
28+
"""
29+
30+
LANGUAGES = {'Stylus'}
31+
REQUIREMENTS = {NpmRequirement('stylint', '1.5.9')}
32+
AUTHORS = {'The coala developers'}
33+
AUTHORS_EMAILS = {'coala-devel@googlegroups.com'}
34+
LICENSE = 'AGPL-3.0'
35+
CAN_DETECT = {'Formatting', 'Syntax', 'Redundancy'}
36+
SEE_MORE = 'https://github.com/SimenB/stylint'
37+
38+
@staticmethod
39+
def create_arguments(filename, file, config_file, stylint_config: str=''):
40+
"""
41+
:param stylint_config:
42+
The location of the ``.stylintrc`` config file.
43+
"""
44+
if stylint_config:
45+
return '--config', stylint_config, filename
46+
else:
47+
return filename,

Diff for: bears/stylus/__init__.py

Whitespace-only changes.

Diff for: package.json

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"remark-cli": "~2",
2121
"remark-lint": "~5",
2222
"stylelint": "~7",
23+
"stylint": "~1.5.9",
2324
"tslint": "~3",
2425
"typescript": ">=1.7.3",
2526
"write-good": "~0.9.1"

Diff for: tests/stylus/StylintBearTest.py

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import os
2+
from queue import Queue
3+
4+
from bears.stylus.StylintBear import StylintBear
5+
from coalib.results.Result import Result
6+
from coalib.results.RESULT_SEVERITY import RESULT_SEVERITY
7+
from coalib.settings.Section import Section
8+
from coalib.testing.BearTestHelper import generate_skip_decorator
9+
from coalib.testing.LocalBearTestHelper import LocalBearTestHelper
10+
11+
12+
def get_testfile_path(name):
13+
return os.path.join(os.path.dirname(__file__),
14+
'stylint_test_files',
15+
name)
16+
17+
18+
def load_testfile(name):
19+
with open(get_testfile_path(name)) as f:
20+
return f.readlines()
21+
22+
23+
@generate_skip_decorator(StylintBear)
24+
class StylintBearTest(LocalBearTestHelper):
25+
26+
def setUp(self):
27+
self.uut = StylintBear(Section('name'), Queue())
28+
29+
def test_bad_missing_colon(self):
30+
filename = 'test_bad_missing_colon.styl'
31+
file_contents = load_testfile(filename)
32+
self.check_results(
33+
self.uut,
34+
file_contents,
35+
[Result.from_values('StylintBear',
36+
message='missing colon between property '
37+
'and value',
38+
file=get_testfile_path(filename),
39+
line=2,
40+
column=6,
41+
severity=RESULT_SEVERITY.NORMAL)],
42+
filename=get_testfile_path(filename))
43+
44+
def test_bad_duplicates(self):
45+
filename = 'test_bad_duplicates.styl'
46+
file_contents = load_testfile(filename)
47+
self.check_results(
48+
self.uut,
49+
file_contents,
50+
[Result.from_values('StylintBear',
51+
message='duplicate property or selector, '
52+
'consider merging',
53+
file=get_testfile_path(filename),
54+
line=4,
55+
severity=RESULT_SEVERITY.NORMAL)],
56+
filename=get_testfile_path(filename))
57+
58+
def test_bad_no_important(self):
59+
filename = 'test_bad_no_important.styl'
60+
file_contents = load_testfile(filename)
61+
self.check_results(
62+
self.uut,
63+
file_contents,
64+
[Result.from_values('StylintBear',
65+
message='!important is disallowed',
66+
file=get_testfile_path(filename),
67+
line=2,
68+
column=9,
69+
severity=RESULT_SEVERITY.NORMAL)],
70+
filename=get_testfile_path(filename))
71+
72+
def test_bad_brackets(self):
73+
filename = 'test_bad_brackets.styl'
74+
file_contents = load_testfile(filename)
75+
self.check_results(
76+
self.uut,
77+
file_contents,
78+
[Result.from_values('StylintBear',
79+
message='unnecessary bracket',
80+
file=get_testfile_path(filename),
81+
line=1,
82+
column=13,
83+
severity=RESULT_SEVERITY.NORMAL),
84+
Result.from_values('StylintBear',
85+
message='unnecessary bracket',
86+
file=get_testfile_path(filename),
87+
line=3,
88+
severity=RESULT_SEVERITY.NORMAL)],
89+
filename=get_testfile_path(filename))
90+
91+
def test_bad_semicolon(self):
92+
filename = 'test_bad_semicolon.styl'
93+
file_contents = load_testfile(filename)
94+
self.check_results(
95+
self.uut,
96+
file_contents,
97+
[Result.from_values('StylintBear',
98+
message='unnecessary semicolon found',
99+
file=get_testfile_path(filename),
100+
line=2,
101+
column=19,
102+
severity=RESULT_SEVERITY.NORMAL)],
103+
filename=get_testfile_path(filename))
104+
105+
def test_bad_alphabetical_order(self):
106+
filename = 'test_bad_alphabetical_order.styl'
107+
file_contents = load_testfile(filename)
108+
self.check_results(
109+
self.uut,
110+
file_contents,
111+
[Result.from_values('StylintBear',
112+
message='prefer alphabetical when sorting '
113+
'properties',
114+
file=get_testfile_path(filename),
115+
line=3,
116+
severity=RESULT_SEVERITY.NORMAL)],
117+
filename=get_testfile_path(filename))
118+
119+
def test_bad_trailing_whitespace(self):
120+
filename = 'test_bad_trailing_whitespace.styl'
121+
file_contents = load_testfile(filename)
122+
self.check_results(
123+
self.uut,
124+
file_contents,
125+
[Result.from_values('StylintBear',
126+
message='trailing whitespace',
127+
file=get_testfile_path(filename),
128+
line=3,
129+
column=22,
130+
severity=RESULT_SEVERITY.NORMAL)],
131+
filename=get_testfile_path(filename))
132+
133+
def test_bad_mixed_spaces_tabs(self):
134+
filename = 'test_bad_mixed_spaces_tabs.styl'
135+
file_contents = load_testfile(filename)
136+
self.check_results(
137+
self.uut,
138+
file_contents,
139+
[Result.from_values('StylintBear',
140+
message='mixed spaces and tabs',
141+
file=get_testfile_path(filename),
142+
line=3,
143+
column=0,
144+
severity=RESULT_SEVERITY.NORMAL)],
145+
filename=get_testfile_path(filename),
146+
settings={'stylint_config': get_testfile_path('.stylintrc')})
147+
148+
def test_valid_file(self):
149+
filename = 'test_valid_file.styl'
150+
file_contents = load_testfile(filename)
151+
self.check_results(
152+
self.uut,
153+
file_contents,
154+
[],
155+
filename=get_testfile_path(filename))

Diff for: tests/stylus/__init__.py

Whitespace-only changes.

Diff for: tests/stylus/stylint_test_files/.stylintrc

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"depthLimit": 4,
3+
"indentPref": 4,
4+
"mixed": true
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.bankTitle
2+
padding-right: 2em
3+
font-weight: bold
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.pageContent {
2+
padding: 1em
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
test = @block
2+
margin: 0
3+
4+
test =
5+
margin: auto
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
test = @block
2+
margin 0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
test = @block
2+
margin: 0
3+
padding-right: 2em
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.im-important
2+
margin 0 !important
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.bankTitle
2+
font-weight: bold;
3+
padding-right: 2em
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.bankTitle
2+
font-weight: bold
3+
padding-right: 2em

Diff for: tests/stylus/stylint_test_files/test_valid_file.styl

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
border-radius()
2+
-moz-border-radius: arguments
3+
-webkit-border-radius: arguments
4+
border-radius: arguments
5+
6+
body
7+
font: 12px Helvetica, Arial, sans-serif
8+
9+
a.button
10+
border-radius: 5px

0 commit comments

Comments
 (0)