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

Issue 116 Name and Reuse Repeating Conditions #131

Merged
merged 24 commits into from
May 28, 2019
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e275f1b
#116 First working version
Oct 30, 2018
bf1f21c
#116 testing travis tests
Oct 30, 2018
b1183b4
#116 cleaning up
Oct 30, 2018
e7eaede
#116 cleaning up
Oct 30, 2018
980e5e3
#116 updated description
Oct 30, 2018
ef16c7e
#116 updated description
Oct 30, 2018
add2194
#116 formatting
Oct 30, 2018
4b3c180
Merge remote-tracking branch 'origin/issue-63' into issue-116
Nov 2, 2018
b00acc0
Merge pull request #132 from Cognifide/master
chutch Nov 5, 2018
1e95bd4
#116 added another test case - using condition more than once
leetcode-user Nov 5, 2018
8607d31
Merge remote-tracking branch 'origin/master' into issue-116
Nov 6, 2018
3dbf928
Merge branch 'issue-116' of https://github.com/Cognifide/AEM-Rules-fo…
Nov 6, 2018
9bf6f8c
#116 formatting
Nov 6, 2018
79116cd
#116 New approach
Nov 6, 2018
cb4e942
#116 Updated description
Nov 6, 2018
e712735
#116 Updated thing mentioned in pull request and changed few details.
Nov 7, 2018
5f2ecfb
Merge remote-tracking branch 'origin/master' into issue-116
leetcode-user Nov 7, 2018
4e13818
#116 reorganised main readme
leetcode-user Nov 7, 2018
8e1877b
Merge remote-tracking branch 'origin/master' into issue-116
May 23, 2019
55e8072
#116 Refactoring and answering PR comments.
May 23, 2019
de0a612
#116 Updated number of HTL rules.
May 23, 2019
8e9ff91
#116 Rule number changed from 5 to 4 as there is no rule #4
May 23, 2019
8afaf88
Merge remote-tracking branch 'origin/master' into issue-116
May 27, 2019
a8b8904
#116 File renamed to match rule number.
May 27, 2019
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
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ gradlew sonarQube -DsonarRunner.aemVersion=6.4

Below you will find descriptions of all rules available in **AEM Rules for SonarQube** plugin.

## HTL Best practices

- **HTL-4** Name and re-use Repeating Conditions
- Consider caching data-sly-test conditions and reduce code duplication.

## Good practices

- **AEM-1** Use predefined constant in annotation instead of hardcoded value.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*-
* #%L
* AEM Rules for SonarQube
* %%
* Copyright (C) 2015-2018 Cognifide Limited
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package com.cognifide.aemrules.htl.checks;

import com.cognifide.aemrules.htl.api.ParsingErrorRule;
import com.cognifide.aemrules.metadata.Metadata;
import com.cognifide.aemrules.tag.Tags;
import com.cognifide.aemrules.version.AemVersion;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.sling.scripting.sightly.compiler.expression.Expression;
import org.sonar.check.Priority;
import org.sonar.check.Rule;
import org.sonar.plugins.html.node.Attribute;
import org.sonar.plugins.html.node.TagNode;

@Rule(
key = NamingAndReusingConditionsCheck.RULE_KEY,
name = NamingAndReusingConditionsCheck.RULE_MESSAGE,
priority = Priority.INFO,
tags = Tags.AEM
)
@AemVersion(
all = true
)
@Metadata(
technicalDebt = "10min"
)
@ParsingErrorRule
public class NamingAndReusingConditionsCheck extends AbstractHtlCheck {

static final String RULE_KEY = "HTL-4";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You define HTL-4 rule key, but doc file is named HTL-5, why?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed


static final String RULE_MESSAGE = "Consider caching data-sly-test conditions";

private static final String SLY_TEST = "data-sly-test";

private static final int SLY_TEST_LENGTH = 14;

private Set<String> unnamedConditions = new HashSet<>();

private Set<String> namedConditions = new HashSet<>();

@Override
public void startHtlElement(List<Expression> expressions, TagNode node) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This API has to be rewritten as it decouples expression from the attribute.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@piotr-wilczynski You should take a look at this :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this method is giving You all of the expressions that exists in node, but if You want the have relation between attribute and expresion You can always check if there is any expression in the attribute and proceed somehow. There is a method called htlExpression default void htlExpression(Expression expression, Node node) It is probably what You are looking for @chutch ?

if (!isConditionReusedCorrectly(expressions, node)) {
createViolation(node.getStartLinePosition(), RULE_MESSAGE);
}
updateConditionSets(expressions, node);
}

private boolean isConditionReusedCorrectly(List<Expression> expressions, TagNode node) {
String condition = clearExpressions(expressions).stream()
.findFirst()
.orElse("");

return !(isUnnamedConditionReused(condition) && isNewUnnamedConditionDeclared(node));
}

private boolean isNewUnnamedConditionDeclared(TagNode node) {
return node.getAttributes().stream()
.map(Attribute::getName)
.anyMatch(SLY_TEST::equals);
}

private boolean isUnnamedConditionReused(String condition) {
return unnamedConditions.stream()
chutch marked this conversation as resolved.
Show resolved Hide resolved
.anyMatch(condition::equals);
}

private void updateConditionSets(List<Expression> expressions, TagNode node) {
String condition = node.getAttributes().stream()
.map(Attribute::getName)
.filter(text -> text.contains(SLY_TEST))
chutch marked this conversation as resolved.
Show resolved Hide resolved
.findFirst()
.orElse("");
if (!SLY_TEST.equals(condition) && SLY_TEST_LENGTH < condition.length()) {
condition = condition.substring(SLY_TEST_LENGTH);
namedConditions.add(condition);
} else {
unnamedConditions.addAll(clearExpressions(expressions).stream()
.filter(text -> !namedConditions.contains(text))
.collect(Collectors.toSet()));
}
}

private Set<String> clearExpressions(List<Expression> expressions){
return expressions.stream()
.map(Expression::getRawText)
.map(text -> text.replaceAll("[${}]", ""))
.collect(Collectors.toSet());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
*/
package com.cognifide.aemrules.htl.rules;

import com.cognifide.aemrules.htl.checks.HtlAttributesShouldBeAtTheEndCheck;
import com.cognifide.aemrules.htl.checks.ParsingErrorCheck;
import com.cognifide.aemrules.htl.Htl;
import com.cognifide.aemrules.htl.api.HtlCheck;
import com.cognifide.aemrules.htl.checks.HtlAttributesShouldBeAtTheEndCheck;
import com.cognifide.aemrules.htl.checks.NamingAndReusingConditionsCheck;
import com.cognifide.aemrules.htl.checks.ParsingErrorCheck;
import com.cognifide.aemrules.htl.checks.PlaceTemplatesInSeparateFilesCheck;
import com.google.common.collect.ImmutableList;
import java.util.List;
Expand All @@ -37,8 +38,9 @@ public final class HtlCheckClasses {

private static final List<Class<? extends HtlCheck>> CLASSES = ImmutableList.of(
ParsingErrorCheck.class,
PlaceTemplatesInSeparateFilesCheck.class,
HtlAttributesShouldBeAtTheEndCheck.class,
PlaceTemplatesInSeparateFilesCheck.class
NamingAndReusingConditionsCheck.class
);

private HtlCheckClasses() {
Expand Down
24 changes: 24 additions & 0 deletions src/main/resources/rules/HTL-5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Always try to re-use existing conditions, so the code is more readable.

== Noncompliant Code Example
```
<!--/* Bad - the same condition is evaluated multiple times */-->
<span class="uber-mode__top-bar" data-sly-test="${uberModeHelper.uberModeEnabled || forceUberMode}">
<div class="my-component">
Some text
</div>
</span>
<span class="uber-mode__bottom-bar" data-sly-test="${uberModeHelper.uberModeEnabled || forceUberMode}"></span>
```



== Compliant Solution
```
<span class="uber-mode__top-bar" data-sly-test.uberMode="${uberModeHelper.uberModeEnabled || forceUberMode}">
<div class="my-component">
Some text
</div>
</span>
<span class="uber-mode__bottom-bar" data-sly-test="${uberMode}"></span>
```
21 changes: 0 additions & 21 deletions src/test/files/checks/htl/HtlAttributesShouldBeAtTheEndCheck.html
Original file line number Diff line number Diff line change
@@ -1,22 +1 @@
<!--

#%L
AEM Rules for SonarQube
%%
Copyright (C) 2015-2018 Cognifide Limited
%%
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
#L%

-->
<div data-sly-list="${model.value}" class="list"></div> <!--/* Non-Compliant */-->
22 changes: 22 additions & 0 deletions src/test/files/checks/htl/NamingAndReusingConditionsCheck.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<span class="uber-mode__top-bar" data-sly-test="${uberModeHelper.uberModeEnabled || forceUberMode}">
<div class="my-component">
Text
</div>
</span>

<span class="uber-mode__bottom-bar" data-sly-test="${uberModeHelper.uberModeEnabled || forceUberMode}"></span> <!--/* Non-Compliant */-->

<span class="uber-mode__top-bar" data-sly-test.uberMode="${uberModeHelper.uberModeEnabled || forceUberMode}">
<div class="my-component">
Text
</div>
</span>
<span class="uber-mode__top-bar" data-sly-test="${uberMode}"></span>

<span class="uber-mode__bottom-bar" data-sly-test="${uberModeHelper.uberModeEnabled || forceUberMode}"> <!--/* Non-Compliant */-->
<div class="my-component">
Text
</div>
</span>

<span class="uber-mode__bottom-bar" data-sly-test="${uberMode}"></span>
chutch marked this conversation as resolved.
Show resolved Hide resolved
11 changes: 11 additions & 0 deletions src/test/java/com/cognifide/aemrules/htl/HtlProfileTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package com.cognifide.aemrules.htl;

import static org.fest.assertions.Assertions.assertThat;

import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
Expand All @@ -42,6 +43,16 @@ public class HtlProfileTest {
public void setUp() {
profile = new HtlProfile();
this.context = new BuiltInQualityProfilesDefinition.Context();

}

@Test
public void sanity() {
profile.define(context);
Map<String, BuiltInActiveRule> activeRules = getActiveRulesByRuleKey(context);

assertThat(activeRules.size()).isEqualTo(4);
assertThat(activeRules.keySet()).contains("HTL-0");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*-
* #%L
* AEM Rules for SonarQube
* %%
* Copyright (C) 2015-2018 Cognifide Limited
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package com.cognifide.aemrules.htl.checks;

import com.cognifide.aemrules.htl.AbstractBaseTest;
import org.junit.Test;

public class NamingAndReusingConditionsCheckTest extends AbstractBaseTest {

@Test
public void checkHtlAttributesOrder() {
check = new NamingAndReusingConditionsCheck();
filename = "src/test/files/checks/htl/NamingAndReusingConditionsCheck.html";
verify();
}
}