Skip to content

Commit 7962831

Browse files
Nico Hellerracodond
authored andcommitted
Fix #68 Add a rule that forbids using types in selectors
1 parent 20f02cb commit 7962831

File tree

27 files changed

+1090
-3
lines changed

27 files changed

+1090
-3
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ It computes the complexity/rule, meaning the average number of selectors per rul
155155
* The number of web fonts should be reduced
156156
* There should be one single declaration per line
157157
* Trailing zeros for numeric values should be removed
158+
* Types in selectors should be removed
158159
* Underscore hack should not be used
159160
* Units for zero length values should be removed
160161
* Universal selector should not be used as key part

css-checks/src/main/java/org/sonar/css/checks/CheckList.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ private static List<Class> getCommonChecks() {
187187
UnknownPropertyCheck.class,
188188
UnknownPseudoCheck.class,
189189
UnknownTypeSelectorCheck.class,
190+
TypeSelectorCheck.class,
190191
UnquotedFontFamilyNamesCheck.class,
191192
UseShorthandPropertyCheck.class,
192193
ValidatePropertyValueCheck.class,
@@ -266,6 +267,7 @@ public static List<Class> getEmbeddedCssChecks() {
266267
UnknownPropertyCheck.class,
267268
UnknownPseudoCheck.class,
268269
UnknownTypeSelectorCheck.class,
270+
TypeSelectorCheck.class,
269271
UnquotedFontFamilyNamesCheck.class,
270272
UseShorthandPropertyCheck.class,
271273
ValidatePropertyValueCheck.class,
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* SonarQube CSS / SCSS / Less Analyzer
3+
* Copyright (C) 2013-2017 David RACODON
4+
* mailto: david.racodon@gmail.com
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU Lesser General Public
8+
* License as published by the Free Software Foundation; either
9+
* version 3 of the License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this program; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19+
*/
20+
package org.sonar.css.checks.common;
21+
22+
import com.google.common.annotations.VisibleForTesting;
23+
import org.sonar.check.Priority;
24+
import org.sonar.check.Rule;
25+
import org.sonar.check.RuleProperty;
26+
import org.sonar.css.checks.Tags;
27+
import org.sonar.plugins.css.api.tree.css.TypeSelectorTree;
28+
import org.sonar.plugins.css.api.visitors.DoubleDispatchVisitorCheck;
29+
import org.sonar.squidbridge.annotations.SqaleConstantRemediation;
30+
31+
@Rule(
32+
key = "type-selector",
33+
name = "Types in selectors should be removed",
34+
priority = Priority.MAJOR,
35+
tags = {Tags.DESIGN})
36+
@SqaleConstantRemediation("30min")
37+
public class TypeSelectorCheck extends DoubleDispatchVisitorCheck {
38+
39+
private static final String DEFAULT_ALLOWED_TYPES = "";
40+
@RuleProperty(
41+
key = "Exclusions",
42+
description = "A list of types that are allowed in selectors (separated by \",\")",
43+
defaultValue = DEFAULT_ALLOWED_TYPES)
44+
private String allowedTypes = DEFAULT_ALLOWED_TYPES;
45+
46+
@Override
47+
public void visitTypeSelector(TypeSelectorTree tree) {
48+
if (!tree.identifier().isInterpolated()
49+
&& !isAllowedType(tree.identifier().text())) {
50+
addPreciseIssue(
51+
tree.identifier(),
52+
"Remove the \"" + tree.identifier().text() + "\" type from this selector.");
53+
}
54+
super.visitTypeSelector(tree);
55+
}
56+
57+
private boolean isAllowedType(String type) {
58+
for (String allowedType : allowedTypes.split(",")) {
59+
if (allowedType.trim().equalsIgnoreCase(type)) {
60+
return true;
61+
}
62+
}
63+
return false;
64+
}
65+
66+
@VisibleForTesting
67+
void setAllowedTypes(String allowedTypes) {
68+
this.allowedTypes = allowedTypes;
69+
}
70+
71+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<p>
2+
Using types in selectors reduces the flexibility and narrows the applicability of CSS styles. Classes should be
3+
preferred as they improve the understandability by giving elements a context-specific name.
4+
For example:
5+
</p>
6+
<pre>
7+
.myBox span {
8+
color: black;
9+
}
10+
</pre>
11+
<p>
12+
This styling can only be applied to a limited subset of all containers with the .someThing class.
13+
Furthermore the reader cannot identify what the span actually represents.
14+
An alternative using a class instead of a type does not have this issue:
15+
</p>
16+
<pre>
17+
.myBox .headline {
18+
color: black;
19+
}
20+
</pre>
21+
<p>The intent is clear and the contextual understandability improved dramatically.</p>
22+
23+
24+
<h2>Noncompliant Code Example</h2>
25+
<pre>
26+
span {
27+
display: block;
28+
}
29+
30+
.mybox div {
31+
color: red;
32+
}
33+
</pre>
34+
35+
<p>
36+
You can exclude certain types via the configuration of this rule as e.g. the anchor type is a valid exception from this rule as it should always denote a link of some sort.
37+
</p>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* SonarQube CSS / SCSS / Less Analyzer
3+
* Copyright (C) 2013-2017 David RACODON
4+
* mailto: david.racodon@gmail.com
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU Lesser General Public
8+
* License as published by the Free Software Foundation; either
9+
* version 3 of the License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this program; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19+
*/
20+
package org.sonar.css.checks.common;
21+
22+
import org.junit.Test;
23+
import org.sonar.css.checks.CheckTestUtils;
24+
import org.sonar.css.checks.verifier.CssCheckVerifier;
25+
26+
public class TypeSelectorCheckTest {
27+
28+
@Test
29+
public void test_css_without_excludes() {
30+
CssCheckVerifier.verifyCssFile(new TypeSelectorCheck(), CheckTestUtils.getCommonTestFile("type-selector/typeSelector.css"));
31+
}
32+
33+
@Test
34+
public void test_css_with_excludes() {
35+
TypeSelectorCheck check = new TypeSelectorCheck();
36+
check.setAllowedTypes("a, span");
37+
CssCheckVerifier.verifyCssFile(check, CheckTestUtils.getCommonTestFile("type-selector/typeSelectorExcluded.css"));
38+
}
39+
40+
@Test
41+
public void test_css_with_excludes_case_insensitive() {
42+
TypeSelectorCheck check = new TypeSelectorCheck();
43+
check.setAllowedTypes("A, SpAn");
44+
CssCheckVerifier.verifyCssFile(check, CheckTestUtils.getCommonTestFile("type-selector/typeSelectorExcluded.css"));
45+
}
46+
47+
@Test
48+
public void test_less_without_excludes() {
49+
CssCheckVerifier.verifyLessFile(new TypeSelectorCheck(), CheckTestUtils.getCommonTestFile("type-selector/typeSelector.less"));
50+
}
51+
52+
@Test
53+
public void test_scss_without_excludes() {
54+
CssCheckVerifier.verifyScssFile(new TypeSelectorCheck(), CheckTestUtils.getCommonTestFile("type-selector/typeSelector.scss"));
55+
}
56+
57+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.mybox {
2+
display: block;
3+
}
4+
5+
div { /* Noncompliant ![sc=1;ec=4;el=+0]! !{Remove the "div" type from this selector.}! */
6+
display: block;
7+
}
8+
9+
#mybox {
10+
display: block;
11+
}
12+
13+
.mybox span { /* Noncompliant ![sc=8;ec=12;el=+0]! !{Remove the "span" type from this selector.}! */
14+
color: red;
15+
}
16+
17+
.mybox #go > a {/* Noncompliant ![sc=14;ec=15;el=+0]! !{Remove the "a" type from this selector.}! */
18+
color: red;
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.mybox {
2+
display: block;
3+
}
4+
5+
div { /* Noncompliant ![sc=1;ec=4;el=+0]! !{Remove the "div" type from this selector.}! */
6+
display: block;
7+
}
8+
9+
#mybox {
10+
display: block;
11+
}
12+
13+
.mybox span { /* Noncompliant ![sc=8;ec=12;el=+0]! !{Remove the "span" type from this selector.}! */
14+
color: red;
15+
}
16+
17+
.mybox #go > a {/* Noncompliant ![sc=14;ec=15;el=+0]! !{Remove the "a" type from this selector.}! */
18+
color: red;
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.mybox {
2+
display: block;
3+
}
4+
5+
div { /* Noncompliant ![sc=1;ec=4;el=+0]! !{Remove the "div" type from this selector.}! */
6+
display: block;
7+
}
8+
9+
#mybox {
10+
display: block;
11+
}
12+
13+
.mybox span { /* Noncompliant ![sc=8;ec=12;el=+0]! !{Remove the "span" type from this selector.}! */
14+
color: red;
15+
}
16+
17+
.mybox #go > a {/* Noncompliant ![sc=14;ec=15;el=+0]! !{Remove the "a" type from this selector.}! */
18+
color: red;
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.mybox {
2+
display: block;
3+
}
4+
5+
div { /* Noncompliant ![sc=1;ec=4;el=+0]! !{Remove the "div" type from this selector.}! */
6+
display: block;
7+
}
8+
9+
#mybox {
10+
display: block;
11+
}
12+
13+
.mybox span {
14+
color: red;
15+
}
16+
17+
.mybox #go > a {
18+
color: red;
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.mybox {
2+
display: block;
3+
}
4+
5+
div { /* Noncompliant ![sc=1;ec=4;el=+0]! !{Remove the "div" type from this selector.}! */
6+
display: block;
7+
}
8+
9+
#mybox {
10+
display: block;
11+
}
12+
13+
.mybox span { /* Noncompliant ![sc=8;ec=12;el=+0]! !{Remove the "span" type from this selector.}! */
14+
color: red;
15+
}
16+
17+
.mybox #go > a {/* Noncompliant ![sc=14;ec=15;el=+0]! !{Remove the "a" type from this selector.}! */
18+
color: red;
19+
}

0 commit comments

Comments
 (0)