From ae070ad0e4663c93aca886d30e7e1d6ed3c90efa Mon Sep 17 00:00:00 2001 From: yassin-kammoun-sonarsource Date: Tue, 31 Oct 2023 14:01:46 +0100 Subject: [PATCH] Create rule CSS:S125: Sections of code should not be commented out --- .../css-issues-project/src/file2.less | 2 +- .../javascript/it/plugin/CssIssuesTest.java | 3 +- .../src/test/expected/css/css-S125.json | 5 + its/sources/css/custom/S125.css | 4 + package-lock.json | 25 ++--- package.json | 2 + packages/css/src/rules/S125/index.ts | 20 ++++ packages/css/src/rules/S125/rule.ts | 69 ++++++++++++ packages/css/src/rules/S125/unit.test.ts | 103 ++++++++++++++++++ packages/css/src/rules/index.ts | 2 + .../src/main/java/org/sonar/css/CssRules.java | 2 + .../org/sonar/css/rules/NoCommentedCode.java | 31 ++++++ .../org/sonar/l10n/css/rules/css/S125.html | 5 + .../org/sonar/l10n/css/rules/css/S125.json | 23 ++++ .../l10n/css/rules/css/Sonar_way_profile.json | 1 + 15 files changed, 278 insertions(+), 19 deletions(-) create mode 100644 its/ruling/src/test/expected/css/css-S125.json create mode 100644 its/sources/css/custom/S125.css create mode 100644 packages/css/src/rules/S125/index.ts create mode 100644 packages/css/src/rules/S125/rule.ts create mode 100644 packages/css/src/rules/S125/unit.test.ts create mode 100644 sonar-plugin/css/src/main/java/org/sonar/css/rules/NoCommentedCode.java create mode 100644 sonar-plugin/css/src/main/resources/org/sonar/l10n/css/rules/css/S125.html create mode 100644 sonar-plugin/css/src/main/resources/org/sonar/l10n/css/rules/css/S125.json diff --git a/its/plugin/projects/css-issues-project/src/file2.less b/its/plugin/projects/css-issues-project/src/file2.less index 8e2c5788c2a..708c170ffe6 100644 --- a/its/plugin/projects/css-issues-project/src/file2.less +++ b/its/plugin/projects/css-issues-project/src/file2.less @@ -30,7 +30,7 @@ a:unknown { /* S4659 | selecto width: calc(100% 80px); /* S5362 | function-calc-no-invalid */ } -// color: pink; /* S4668 | no-invalid-double-slash-comments | Doesn't raise for LESS */ +// color: pink; /* S4668 | no-invalid-double-slash-comments | Doesn't raise for LESS */ /* SS125 | no-commented-code */ .class1 { width: 100px; diff --git a/its/plugin/tests/src/test/java/com/sonar/javascript/it/plugin/CssIssuesTest.java b/its/plugin/tests/src/test/java/com/sonar/javascript/it/plugin/CssIssuesTest.java index 19ea7bf3035..ae7d4dd5cad 100644 --- a/its/plugin/tests/src/test/java/com/sonar/javascript/it/plugin/CssIssuesTest.java +++ b/its/plugin/tests/src/test/java/com/sonar/javascript/it/plugin/CssIssuesTest.java @@ -168,7 +168,8 @@ void issue_list() { tuple("css:S5362", "css-issues-project:src/file1.css"), tuple("css:S5362", "css-issues-project:src/file2.less"), tuple("css:S5362", "css-issues-project:src/file3.scss"), - tuple("css:S1116", "css-issues-project:src/file5-1.html") + tuple("css:S1116", "css-issues-project:src/file5-1.html"), + tuple("css:S125", "css-issues-project:src/file2.less") ); } } diff --git a/its/ruling/src/test/expected/css/css-S125.json b/its/ruling/src/test/expected/css/css-S125.json new file mode 100644 index 00000000000..a4f097b25fa --- /dev/null +++ b/its/ruling/src/test/expected/css/css-S125.json @@ -0,0 +1,5 @@ +{ +"project:custom/S125.css": [ +3 +] +} diff --git a/its/sources/css/custom/S125.css b/its/sources/css/custom/S125.css new file mode 100644 index 00000000000..0c381d054ca --- /dev/null +++ b/its/sources/css/custom/S125.css @@ -0,0 +1,4 @@ +p { + color: red; +/* font-size: large; */ +} diff --git a/package-lock.json b/package-lock.json index 9d3f9b38868..27df1cb0a47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "jsx-ast-utils", "lodash.clone", "module-alias", + "postcss", "postcss-html", "postcss-less", "postcss-sass", @@ -70,6 +71,7 @@ "jsx-ast-utils": "3.3.5", "lodash.clone": "4.5.0", "module-alias": "2.2.3", + "postcss": "8.4.31", "postcss-html": "0.36.0", "postcss-less": "6.0.0", "postcss-sass": "0.5.0", @@ -9849,23 +9851,10 @@ } }, "node_modules/postcss": { - "version": "8.4.30", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "version": "8.4.31", + "resolved": "https://repox.jfrog.io/repox/api/npm/npm/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "inBundle": true, - "license": "MIT", "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -18189,7 +18178,9 @@ } }, "postcss": { - "version": "8.4.30", + "version": "8.4.31", + "resolved": "https://repox.jfrog.io/repox/api/npm/npm/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "requires": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", diff --git a/package.json b/package.json index 59b867ba165..209846e91f0 100644 --- a/package.json +++ b/package.json @@ -91,6 +91,7 @@ "jsx-ast-utils": "3.3.5", "lodash.clone": "4.5.0", "module-alias": "2.2.3", + "postcss": "8.4.31", "postcss-html": "0.36.0", "postcss-less": "6.0.0", "postcss-sass": "0.5.0", @@ -129,6 +130,7 @@ "jsx-ast-utils", "lodash.clone", "module-alias", + "postcss", "postcss-html", "postcss-less", "postcss-sass", diff --git a/packages/css/src/rules/S125/index.ts b/packages/css/src/rules/S125/index.ts new file mode 100644 index 00000000000..13438fe7e69 --- /dev/null +++ b/packages/css/src/rules/S125/index.ts @@ -0,0 +1,20 @@ +/* + * SonarQube JavaScript Plugin + * Copyright (C) 2011-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +export { rule } from './rule'; diff --git a/packages/css/src/rules/S125/rule.ts b/packages/css/src/rules/S125/rule.ts new file mode 100644 index 00000000000..55799df1867 --- /dev/null +++ b/packages/css/src/rules/S125/rule.ts @@ -0,0 +1,69 @@ +/* + * SonarQube JavaScript Plugin + * Copyright (C) 2011-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +// https://sonarsource.github.io/rspec/#/rspec/S125/css + +import * as stylelint from 'stylelint'; +import { parse } from 'postcss'; + +const ruleName = 'no-commented-code'; +const messages = { commentedCode: 'Remove this commented out code.' }; + +const ruleImpl: stylelint.RuleBase = () => { + return (root: any, result: any) => { + root.walkComments((comment: any) => { + const { text } = comment; + if (isLikelyCss(text)) { + try { + parse(text); + stylelint.utils.report({ + ruleName, + result, + message: messages.commentedCode, + node: comment, + }); + } catch { + /* syntax error */ + } + } + }); + }; + + function isLikelyCss(text: string) { + // Regular expression to match CSS selectors, properties, and values + const ruleRegex = /([a-z0-9\s,.\-#:_]+)\{([^}]*)\}/i; + + // Regular expression to match CSS declarations + const declRegex = /([a-z-]+)\s*:\s*([^;]+);/i; + + // Regular expression to match CSS at-rules + const atRuleRegex = /@([a-z-]*)\s*([^;{]*)(;|(\{([^}]*)\}))/i; + + // Test the text against the regular expressions + return ruleRegex.test(text) || declRegex.test(text) || atRuleRegex.test(text); + } +}; + +export const rule = stylelint.createPlugin( + ruleName, + Object.assign(ruleImpl, { + messages, + ruleName, + }), +) as { ruleName: string; rule: stylelint.Rule }; diff --git a/packages/css/src/rules/S125/unit.test.ts b/packages/css/src/rules/S125/unit.test.ts new file mode 100644 index 00000000000..d75bd801ed6 --- /dev/null +++ b/packages/css/src/rules/S125/unit.test.ts @@ -0,0 +1,103 @@ +/* + * SonarQube JavaScript Plugin + * Copyright (C) 2011-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import { StylelintRuleTester } from '../../../tests/tools/tester'; +import { rule } from './rule'; + +const ruleTester = new StylelintRuleTester(rule); +ruleTester.run('no-commented-code', { + valid: [ + { + description: 'no comment', + code: 'p {}', + }, + { + description: 'no commented code', + code: '/* hello, world! */', + }, + ], + invalid: [ + { + description: 'selector', + code: '/* p {} */', + errors: [{ text: 'Remove this commented out code.', line: 1, column: 1 }], + }, + { + description: 'multiple selectors', + code: '/* p, div {} */', + errors: [{ text: 'Remove this commented out code.', line: 1, column: 1 }], + }, + { + description: 'declaration', + code: '/* color: blue; */', + errors: [{ text: 'Remove this commented out code.', line: 1, column: 1 }], + }, + { + description: 'selector declaration', + code: '/* p { color: blue; } */', + errors: [{ text: 'Remove this commented out code.', line: 1, column: 1 }], + }, + { + description: 'multiple declarations', + code: '/* div { font-size: 20px; color: red; } */', + errors: [{ text: 'Remove this commented out code.', line: 1, column: 1 }], + }, + { + description: 'class selector', + code: '/* .class { background-color: red; } */', + errors: [{ text: 'Remove this commented out code.', line: 1, column: 1 }], + }, + { + description: 'id selector', + code: '/* #id:hover { border: 1px solid black; } */', + errors: [{ text: 'Remove this commented out code.', line: 1, column: 1 }], + }, + { + description: 'attribute selector', + code: '/* a[href] { color: purple; } */', + errors: [{ text: 'Remove this commented out code.', line: 1, column: 1 }], + }, + { + description: 'media query', + code: '/* @media (max-width: 600px) { .class { font-size: 18px; } } */', + errors: [{ text: 'Remove this commented out code.', line: 1, column: 1 }], + }, + { + description: '@keyframes', + code: '/* @keyframes mymove { 0% { top: 0px; } 100% { top: 200px; } } */', + errors: [{ text: 'Remove this commented out code.', line: 1, column: 1 }], + }, + { + description: 'import', + code: '/* @import url("styles.css"); */', + errors: [{ text: 'Remove this commented out code.', line: 1, column: 1 }], + }, + { + description: 'multline', + code: ` +/* +p { + color: blue; +} +*/ + `, + errors: [{ text: 'Remove this commented out code.', line: 2, column: 1 }], + }, + ], +}); diff --git a/packages/css/src/rules/index.ts b/packages/css/src/rules/index.ts index 15e64e6add4..c5f7b0d7bbe 100644 --- a/packages/css/src/rules/index.ts +++ b/packages/css/src/rules/index.ts @@ -18,6 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as stylelint from 'stylelint'; +import { rule as S125 } from './S125'; import { rule as S5362 } from './S5362'; /** @@ -28,6 +29,7 @@ const rules: { [key: string]: stylelint.Rule } = {}; /** * Maps Stylelint rule keys to rule implementations */ +rules[S125.ruleName] = S125.rule; // no-commented-code rules[S5362.ruleName] = S5362.rule; // function-calc-no-invalid export { rules }; diff --git a/sonar-plugin/css/src/main/java/org/sonar/css/CssRules.java b/sonar-plugin/css/src/main/java/org/sonar/css/CssRules.java index b0703cc0e35..cf41375e926 100644 --- a/sonar-plugin/css/src/main/java/org/sonar/css/CssRules.java +++ b/sonar-plugin/css/src/main/java/org/sonar/css/CssRules.java @@ -44,6 +44,7 @@ import org.sonar.css.rules.FunctionLinearGradientNoNonstandardDirection; import org.sonar.css.rules.KeyframeDeclarationNoImportant; import org.sonar.css.rules.MediaFeatureNameNoUnknown; +import org.sonar.css.rules.NoCommentedCode; import org.sonar.css.rules.NoDescendingSpecificity; import org.sonar.css.rules.NoDuplicateAtImportRules; import org.sonar.css.rules.NoDuplicateSelectors; @@ -89,6 +90,7 @@ public static List> getRuleClasses() { FunctionLinearGradientNoNonstandardDirection.class, KeyframeDeclarationNoImportant.class, MediaFeatureNameNoUnknown.class, + NoCommentedCode.class, NoDescendingSpecificity.class, NoDuplicateAtImportRules.class, NoDuplicateSelectors.class, diff --git a/sonar-plugin/css/src/main/java/org/sonar/css/rules/NoCommentedCode.java b/sonar-plugin/css/src/main/java/org/sonar/css/rules/NoCommentedCode.java new file mode 100644 index 00000000000..151524786b4 --- /dev/null +++ b/sonar-plugin/css/src/main/java/org/sonar/css/rules/NoCommentedCode.java @@ -0,0 +1,31 @@ +/* + * SonarQube JavaScript Plugin + * Copyright (C) 2011-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.css.rules; + +import org.sonar.check.Rule; + +@Rule(key = "S125") +public class NoCommentedCode implements CssRule { + + @Override + public String stylelintKey() { + return "no-commented-code"; + } +} diff --git a/sonar-plugin/css/src/main/resources/org/sonar/l10n/css/rules/css/S125.html b/sonar-plugin/css/src/main/resources/org/sonar/l10n/css/rules/css/S125.html new file mode 100644 index 00000000000..0d83de02ce7 --- /dev/null +++ b/sonar-plugin/css/src/main/resources/org/sonar/l10n/css/rules/css/S125.html @@ -0,0 +1,5 @@ +

Why is this an issue?

+

Commented-out code distracts the focus from the actual executed code. It creates a noise that increases maintenance code. And because it is never +executed, it quickly becomes out of date and invalid.

+

Commented-out code should be deleted and can be retrieved from source control history if required.

+ diff --git a/sonar-plugin/css/src/main/resources/org/sonar/l10n/css/rules/css/S125.json b/sonar-plugin/css/src/main/resources/org/sonar/l10n/css/rules/css/S125.json new file mode 100644 index 00000000000..2aa85653622 --- /dev/null +++ b/sonar-plugin/css/src/main/resources/org/sonar/l10n/css/rules/css/S125.json @@ -0,0 +1,23 @@ +{ + "title": "Sections of code should not be commented out", + "type": "CODE_SMELL", + "code": { + "impacts": { + "MAINTAINABILITY": "MEDIUM" + }, + "attribute": "CLEAR" + }, + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "unused" + ], + "defaultSeverity": "Major", + "ruleSpecification": "RSPEC-125", + "sqKey": "S125", + "scope": "All", + "quickfix": "unknown" +} diff --git a/sonar-plugin/css/src/main/resources/org/sonar/l10n/css/rules/css/Sonar_way_profile.json b/sonar-plugin/css/src/main/resources/org/sonar/l10n/css/rules/css/Sonar_way_profile.json index 9b98de03650..74e8e80e600 100644 --- a/sonar-plugin/css/src/main/resources/org/sonar/l10n/css/rules/css/Sonar_way_profile.json +++ b/sonar-plugin/css/src/main/resources/org/sonar/l10n/css/rules/css/Sonar_way_profile.json @@ -1,6 +1,7 @@ { "name": "Sonar way", "ruleKeys": [ + "S125", "S1116", "S1128", "S4647",