Skip to content

Commit 5b5dbd0

Browse files
committed
Fix #102 Add parameter to 'experimental-pseudo-usage' rules to flag some pseudo elements as non-experimental
1 parent 729f0cb commit 5b5dbd0

25 files changed

+329
-8
lines changed

css-checks/src/main/java/org/sonar/css/checks/common/ExperimentalPseudoCheck.java

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,23 @@
1919
*/
2020
package org.sonar.css.checks.common;
2121

22+
import com.google.common.annotations.VisibleForTesting;
2223
import org.sonar.check.Priority;
2324
import org.sonar.check.Rule;
25+
import org.sonar.check.RuleProperty;
26+
import org.sonar.css.checks.CheckList;
27+
import org.sonar.css.checks.CheckUtils;
2428
import org.sonar.css.checks.Tags;
29+
import org.sonar.plugins.css.api.tree.Tree;
2530
import org.sonar.plugins.css.api.tree.css.PseudoFunctionTree;
2631
import org.sonar.plugins.css.api.tree.css.PseudoIdentifierTree;
27-
import org.sonar.plugins.css.api.tree.Tree;
2832
import org.sonar.plugins.css.api.visitors.DoubleDispatchVisitorCheck;
2933
import org.sonar.squidbridge.annotations.ActivatedByDefault;
3034
import org.sonar.squidbridge.annotations.SqaleConstantRemediation;
3135

36+
import java.util.regex.Pattern;
37+
import java.util.regex.PatternSyntaxException;
38+
3239
@Rule(
3340
key = "experimental-pseudo-usage",
3441
name = "Experimental pseudo-elements and pseudo-classes should not be used",
@@ -38,17 +45,27 @@
3845
@ActivatedByDefault
3946
public class ExperimentalPseudoCheck extends DoubleDispatchVisitorCheck {
4047

48+
private static final String DEFAULT_PSEUDOS_TO_EXCLUDE = "";
49+
50+
@RuleProperty(
51+
key = "pseudosToExclude",
52+
description = "A regular expression to exclude pseudo-elements and pseudo-classes from being considered as experimental. Example: \"any-link|user.*\". See " + CheckUtils.LINK_TO_JAVA_REGEX_PATTERN_DOC + " for detailed regular expression syntax.",
53+
defaultValue = DEFAULT_PSEUDOS_TO_EXCLUDE)
54+
private String pseudosToExclude = DEFAULT_PSEUDOS_TO_EXCLUDE;
55+
4156
@Override
4257
public void visitPseudoFunction(PseudoFunctionTree tree) {
43-
if (tree.isVendorPrefixed() || tree.standardFunction().isExperimental()) {
58+
if (!tree.standardFunction().getName().matches(pseudosToExclude)
59+
&& (tree.isVendorPrefixed() || tree.standardFunction().isExperimental())) {
4460
createIssue(tree.function(), tree.standardFunction().getName());
4561
}
4662
super.visitPseudoFunction(tree);
4763
}
4864

4965
@Override
5066
public void visitPseudoIdentifier(PseudoIdentifierTree tree) {
51-
if (tree.isVendorPrefixed() || tree.standardPseudoIdentifier().isExperimental()) {
67+
if (!tree.standardPseudoIdentifier().getName().matches(pseudosToExclude)
68+
&& (tree.isVendorPrefixed() || tree.standardPseudoIdentifier().isExperimental())) {
5269
createIssue(tree.identifier(), tree.standardPseudoIdentifier().getName());
5370
}
5471
super.visitPseudoIdentifier(tree);
@@ -58,4 +75,25 @@ private void createIssue(Tree location, String pseudo) {
5875
addPreciseIssue(location, "Remove this usage of the experimental \"" + pseudo + "\" pseudo.");
5976
}
6077

78+
@Override
79+
public void validateParameters() {
80+
try {
81+
Pattern.compile(pseudosToExclude);
82+
} catch (PatternSyntaxException exception) {
83+
throw new IllegalStateException(paramsErrorMessage(), exception);
84+
}
85+
}
86+
87+
@VisibleForTesting
88+
void setPseudosToExclude(String pseudosToExclude) {
89+
this.pseudosToExclude = pseudosToExclude;
90+
}
91+
92+
private String paramsErrorMessage() {
93+
return CheckUtils.paramsErrorMessage(
94+
this.getClass(),
95+
CheckList.CSS_REPOSITORY_KEY,
96+
"pseudosToExclude parameter \"" + pseudosToExclude + "\" is not a valid regular expression.");
97+
}
98+
6199
}

css-checks/src/test/java/org/sonar/css/checks/common/ExperimentalPseudoCheckTest.java

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,56 @@
2525

2626
import java.io.File;
2727

28-
public class ExperimentalPseudoCheckTest {
28+
import static org.fest.assertions.Assertions.assertThat;
2929

30-
private ExperimentalPseudoCheck check = new ExperimentalPseudoCheck();
30+
public class ExperimentalPseudoCheckTest {
3131

3232
@Test
3333
public void test_css() {
34-
CssCheckVerifier.verifyCssFile(check, getTestFile("experimentalPseudoUsage.css"));
34+
CssCheckVerifier.verifyCssFile(new ExperimentalPseudoCheck(), getTestFile("experimentalPseudoUsage.css"));
35+
}
36+
37+
@Test
38+
public void test_css_exclude_pseudos() {
39+
ExperimentalPseudoCheck check = new ExperimentalPseudoCheck();
40+
check.setPseudosToExclude("any-link|cont.*");
41+
CssCheckVerifier.verifyCssFile(check, getTestFile("experimentalPseudoUsageExcludePseudos.css"));
3542
}
3643

3744
@Test
3845
public void test_less() {
39-
CssCheckVerifier.verifyLessFile(check, getTestFile("experimentalPseudoUsage.less"));
46+
CssCheckVerifier.verifyLessFile(new ExperimentalPseudoCheck(), getTestFile("experimentalPseudoUsage.less"));
47+
}
48+
49+
@Test
50+
public void test_less_exclude_pseudos() {
51+
ExperimentalPseudoCheck check = new ExperimentalPseudoCheck();
52+
check.setPseudosToExclude("any-link|cont.*");
53+
CssCheckVerifier.verifyLessFile(check, getTestFile("experimentalPseudoUsageExcludePseudos.less"));
4054
}
4155

4256
@Test
4357
public void test_scss() {
44-
CssCheckVerifier.verifyScssFile(check, getTestFile("experimentalPseudoUsage.scss"));
58+
CssCheckVerifier.verifyScssFile(new ExperimentalPseudoCheck(), getTestFile("experimentalPseudoUsage.scss"));
59+
}
60+
61+
@Test
62+
public void test_scss_exclude_pseudos() {
63+
ExperimentalPseudoCheck check = new ExperimentalPseudoCheck();
64+
check.setPseudosToExclude("any-link|cont.*");
65+
CssCheckVerifier.verifyScssFile(check, getTestFile("experimentalPseudoUsageExcludePseudos.scss"));
66+
}
67+
68+
@Test
69+
public void should_throw_an_illegal_state_exception_as_the_pseudosToExclude_parameter_is_not_valid() {
70+
try {
71+
ExperimentalPseudoCheck check = new ExperimentalPseudoCheck();
72+
check.setPseudosToExclude("(");
73+
CssCheckVerifier.issuesOnCssFile(check, getTestFile("experimentalPseudoUsage.css")).noMore();
74+
} catch (IllegalStateException e) {
75+
assertThat(e.getMessage()).isEqualTo("Check css:experimental-pseudo-usage (Experimental pseudo-elements and pseudo-classes should not be used): "
76+
+ "pseudosToExclude parameter \"(\" is not a valid regular expression.");
77+
}
4578
}
4679

4780
private File getTestFile(String fileName) {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#id:-moz-abc { /* Noncompliant ![sc=5;ec=13;el=+0]! !{Remove this usage of the experimental "abc" pseudo.}! */
2+
color: red;
3+
}
4+
5+
p:-moz-abc(ltr) { /* Noncompliant ![sc=3;ec=11;el=+0]! !{Remove this usage of the experimental "abc" pseudo.}! */
6+
color: red;
7+
}
8+
9+
:host { /* Noncompliant ![sc=2;ec=6;el=+0]! !{Remove this usage of the experimental "host" pseudo.}! */
10+
color: red;
11+
}
12+
13+
:content {
14+
color: red;
15+
}
16+
17+
:any-link() {
18+
color: red;
19+
}
20+
21+
p:empty {
22+
color: red;
23+
}
24+
25+
p:not(.mybox) {
26+
color: red;
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#id:-moz-abc { /* Noncompliant ![sc=5;ec=13;el=+0]! !{Remove this usage of the experimental "abc" pseudo.}! */
2+
color: red;
3+
}
4+
5+
p:-moz-abc(ltr) { /* Noncompliant ![sc=3;ec=11;el=+0]! !{Remove this usage of the experimental "abc" pseudo.}! */
6+
color: red;
7+
}
8+
9+
:host { /* Noncompliant ![sc=2;ec=6;el=+0]! !{Remove this usage of the experimental "host" pseudo.}! */
10+
color: red;
11+
}
12+
13+
:content {
14+
color: red;
15+
}
16+
17+
:any-link() {
18+
color: red;
19+
}
20+
21+
p:empty {
22+
color: red;
23+
}
24+
25+
p:not(.mybox) {
26+
color: red;
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#id:-moz-abc { /* Noncompliant ![sc=5;ec=13;el=+0]! !{Remove this usage of the experimental "abc" pseudo.}! */
2+
color: red;
3+
}
4+
5+
p:-moz-abc(ltr) { /* Noncompliant ![sc=3;ec=11;el=+0]! !{Remove this usage of the experimental "abc" pseudo.}! */
6+
color: red;
7+
}
8+
9+
:host { /* Noncompliant ![sc=2;ec=6;el=+0]! !{Remove this usage of the experimental "host" pseudo.}! */
10+
color: red;
11+
}
12+
13+
:content {
14+
color: red;
15+
}
16+
17+
:any-link() {
18+
color: red;
19+
}
20+
21+
p:empty {
22+
color: red;
23+
}
24+
25+
p:not(.mybox) {
26+
color: red;
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#id:-moz-abc { /* Noncompliant ![sc=5;ec=13;el=+0]! !{Remove this usage of the experimental "abc" pseudo.}! */
2+
color: red;
3+
}
4+
5+
p:-moz-abc(ltr) { /* Noncompliant ![sc=3;ec=11;el=+0]! !{Remove this usage of the experimental "abc" pseudo.}! */
6+
color: red;
7+
}
8+
9+
:host { /* Noncompliant ![sc=2;ec=6;el=+0]! !{Remove this usage of the experimental "host" pseudo.}! */
10+
color: red;
11+
}
12+
13+
:content {
14+
color: red;
15+
}
16+
17+
:any-link() {
18+
color: red;
19+
}
20+
21+
p:empty {
22+
color: red;
23+
}
24+
25+
p:not(.mybox) {
26+
color: red;
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#id:-moz-abc { /* Noncompliant ![sc=5;ec=13;el=+0]! !{Remove this usage of the experimental "abc" pseudo.}! */
2+
color: red;
3+
}
4+
5+
p:-moz-abc(ltr) { /* Noncompliant ![sc=3;ec=11;el=+0]! !{Remove this usage of the experimental "abc" pseudo.}! */
6+
color: red;
7+
}
8+
9+
:host { /* Noncompliant ![sc=2;ec=6;el=+0]! !{Remove this usage of the experimental "host" pseudo.}! */
10+
color: red;
11+
}
12+
13+
:content {
14+
color: red;
15+
}
16+
17+
:any-link() {
18+
color: red;
19+
}
20+
21+
p:empty {
22+
color: red;
23+
}
24+
25+
p:not(.mybox) {
26+
color: red;
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#id:-moz-abc { /* Noncompliant ![sc=5;ec=13;el=+0]! !{Remove this usage of the experimental "abc" pseudo.}! */
2+
color: red;
3+
}
4+
5+
p:-moz-abc(ltr) { /* Noncompliant ![sc=3;ec=11;el=+0]! !{Remove this usage of the experimental "abc" pseudo.}! */
6+
color: red;
7+
}
8+
9+
:host { /* Noncompliant ![sc=2;ec=6;el=+0]! !{Remove this usage of the experimental "host" pseudo.}! */
10+
color: red;
11+
}
12+
13+
:content {
14+
color: red;
15+
}
16+
17+
:any-link() {
18+
color: red;
19+
}
20+
21+
p:empty {
22+
color: red;
23+
}
24+
25+
p:not(.mybox) {
26+
color: red;
27+
}

its/ruling/tests/src/test/expected/css-experimental-pseudo-usage.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
13,
77
17,
88
],
9+
'project:custom/common/experimental-pseudo-usage/experimentalPseudoUsageExcludePseudos.css':[
10+
1,
11+
5,
12+
9,
13+
13,
14+
],
915
'project:custom/common/unknown-pseudo/unknownPseudo.css':[
1016
7,
1117
17,

its/ruling/tests/src/test/expected/css-ids.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
1,
1010
5,
1111
],
12+
'project:custom/common/experimental-pseudo-usage/experimentalPseudoUsageExcludePseudos.css':[
13+
1,
14+
],
1215
'project:custom/common/id-selector-naming-convention/selectorNamingConvention.css':[
1316
1,
1417
7,

0 commit comments

Comments
 (0)