├── .cirrus.star ├── .cirrus.yml ├── .cirrus ├── nodejs-10.Dockerfile └── nodejs-10.jdk17.Dockerfile ├── .github ├── CODEOWNERS └── workflows │ └── release.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── its ├── plugin │ ├── pom.xml │ ├── projects │ │ ├── (dir with paren) │ │ │ └── src │ │ │ │ └── file1.css │ │ ├── external-report-project │ │ │ ├── report.json │ │ │ ├── src │ │ │ │ ├── file1.css │ │ │ │ └── file2.css │ │ │ └── stylelintconfig.json │ │ ├── issues-project │ │ │ └── src │ │ │ │ ├── cssModules.css │ │ │ │ ├── empty1.css │ │ │ │ ├── empty2.less │ │ │ │ ├── empty3.scss │ │ │ │ ├── file-with-parsing-error-excluded.css │ │ │ │ ├── file-with-parsing-error.css │ │ │ │ ├── file-with-parsing-error.less │ │ │ │ ├── file1.css │ │ │ │ ├── file2.less │ │ │ │ ├── file3.scss │ │ │ │ ├── file4.foo │ │ │ │ ├── file5-1.html │ │ │ │ ├── file5.htm │ │ │ │ ├── file6.vue │ │ │ │ └── file7.jsx │ │ ├── metrics-project │ │ │ └── src │ │ │ │ ├── file1.css │ │ │ │ ├── file2.less │ │ │ │ ├── file3.scss │ │ │ │ └── file4.html │ │ ├── minified-project │ │ │ └── src │ │ │ │ ├── normal.css │ │ │ │ ├── normal.min.css │ │ │ │ └── oneline.css │ │ └── php-project │ │ │ └── src │ │ │ └── index.php │ └── src │ │ └── test │ │ └── java │ │ └── org │ │ └── sonar │ │ └── css │ │ └── its │ │ ├── IssuesTest.java │ │ ├── MetricsTest.java │ │ ├── MinifiedTest.java │ │ ├── NoCssFileProjectTest.java │ │ ├── NonStandardPathTest.java │ │ ├── StylelintReportTest.java │ │ └── Tests.java ├── pom.xml ├── ruling │ ├── pom.xml │ └── src │ │ └── test │ │ ├── java │ │ └── org │ │ │ └── sonar │ │ │ └── css │ │ │ └── its │ │ │ └── CssRulingTest.java │ │ └── resources │ │ └── expected │ │ ├── css-S4647.json │ │ ├── css-S4648.json │ │ ├── css-S4653.json │ │ ├── css-S4654.json │ │ ├── css-S4656.json │ │ ├── css-S4658.json │ │ ├── css-S4661.json │ │ ├── css-S4662.json │ │ ├── css-S4664.json │ │ ├── css-S4666.json │ │ ├── css-S4667.json │ │ └── css-S4670.json └── sources │ └── custom │ ├── S4653.scss │ ├── S4654.css │ ├── S4654.scss │ ├── S4660.scss │ ├── S4662.scss │ ├── S4666.css │ ├── S4670.css │ ├── S5362.less │ ├── S5362.scss │ └── test.css ├── pom.xml ├── sonar-css-plugin ├── css-bundle │ ├── bin │ │ └── server │ ├── jest.config.js │ ├── package.json │ ├── package │ │ ├── .gitignore │ │ ├── node_modules │ │ │ ├── .bin │ │ │ │ └── run-node │ │ │ ├── .yarn-integrity │ │ │ └── run-node │ │ │ │ ├── license │ │ │ │ ├── package.json │ │ │ │ ├── readme.md │ │ │ │ └── run-node │ │ ├── package.json │ │ └── yarn.lock │ ├── src │ │ └── server.ts │ ├── tests │ │ ├── fixtures │ │ │ ├── file-bom.css │ │ │ ├── file.css │ │ │ ├── file.html │ │ │ ├── file.php │ │ │ └── stylelintconfig.json │ │ ├── server-mock-stylelint.test.ts │ │ ├── server.test.ts │ │ └── utils.ts │ ├── tsconfig.json │ └── yarn.lock ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── sonar │ │ │ └── css │ │ │ └── plugin │ │ │ ├── CssLanguage.java │ │ │ ├── CssPlugin.java │ │ │ ├── CssRuleSensor.java │ │ │ ├── CssRules.java │ │ │ ├── CssRulesDefinition.java │ │ │ ├── MinifiedFilesFilter.java │ │ │ ├── SonarWayProfile.java │ │ │ ├── StylelintReport.java │ │ │ ├── StylelintReportSensor.java │ │ │ ├── metrics │ │ │ ├── CssLexer.java │ │ │ ├── CssToken.java │ │ │ ├── CssTokenType.java │ │ │ ├── MetricSensor.java │ │ │ └── Tokenizer.java │ │ │ ├── package-info.java │ │ │ ├── rules │ │ │ ├── AtRuleNoUnknown.java │ │ │ ├── BlockNoEmpty.java │ │ │ ├── ColorNoInvalidHex.java │ │ │ ├── CommentNoEmpty.java │ │ │ ├── CssRule.java │ │ │ ├── DeclarationBlockNoDuplicateProperties.java │ │ │ ├── DeclarationBlockNoShorthandPropertyOverrides.java │ │ │ ├── FontFamilyNoDuplicateNames.java │ │ │ ├── FontFamilyNoMissingGenericFamilyKeyword.java │ │ │ ├── FunctionCalcNoInvalid.java │ │ │ ├── FunctionCalcNoUnspacedOperator.java │ │ │ ├── FunctionLinearGradientNoNonstandardDirection.java │ │ │ ├── KeyframeDeclarationNoImportant.java │ │ │ ├── MediaFeatureNameNoUnknown.java │ │ │ ├── NoDescendingSpecificity.java │ │ │ ├── NoDuplicateAtImportRules.java │ │ │ ├── NoDuplicateSelectors.java │ │ │ ├── NoEmptySource.java │ │ │ ├── NoExtraSemicolons.java │ │ │ ├── NoInvalidDoubleSlashComments.java │ │ │ ├── PropertyNoUnknown.java │ │ │ ├── RuleUtils.java │ │ │ ├── SelectorPseudoClassNoUnknown.java │ │ │ ├── SelectorPseudoElementNoUnknown.java │ │ │ ├── SelectorTypeNoUnknown.java │ │ │ ├── StringNoNewline.java │ │ │ ├── UnitNoUnknown.java │ │ │ └── package-info.java │ │ │ └── server │ │ │ ├── CssAnalyzerBridgeServer.java │ │ │ ├── NetUtils.java │ │ │ ├── NodeDeprecationWarning.java │ │ │ ├── bundle │ │ │ ├── Bundle.java │ │ │ ├── CssAnalyzerBundle.java │ │ │ ├── Zip.java │ │ │ └── package-info.java │ │ │ └── package-info.java │ └── resources │ │ ├── org │ │ └── sonar │ │ │ └── l10n │ │ │ └── css │ │ │ └── rules │ │ │ ├── css │ │ │ ├── S1116.html │ │ │ ├── S1116.json │ │ │ ├── S1128.html │ │ │ ├── S1128.json │ │ │ ├── S4647.html │ │ │ ├── S4647.json │ │ │ ├── S4648.html │ │ │ ├── S4648.json │ │ │ ├── S4649.html │ │ │ ├── S4649.json │ │ │ ├── S4650.html │ │ │ ├── S4650.json │ │ │ ├── S4651.html │ │ │ ├── S4651.json │ │ │ ├── S4652.html │ │ │ ├── S4652.json │ │ │ ├── S4653.html │ │ │ ├── S4653.json │ │ │ ├── S4654.html │ │ │ ├── S4654.json │ │ │ ├── S4655.html │ │ │ ├── S4655.json │ │ │ ├── S4656.html │ │ │ ├── S4656.json │ │ │ ├── S4657.html │ │ │ ├── S4657.json │ │ │ ├── S4658.html │ │ │ ├── S4658.json │ │ │ ├── S4659.html │ │ │ ├── S4659.json │ │ │ ├── S4660.html │ │ │ ├── S4660.json │ │ │ ├── S4661.html │ │ │ ├── S4661.json │ │ │ ├── S4662.html │ │ │ ├── S4662.json │ │ │ ├── S4663.html │ │ │ ├── S4663.json │ │ │ ├── S4664.html │ │ │ ├── S4664.json │ │ │ ├── S4666.html │ │ │ ├── S4666.json │ │ │ ├── S4667.html │ │ │ ├── S4667.json │ │ │ ├── S4668.html │ │ │ ├── S4668.json │ │ │ ├── S4670.html │ │ │ ├── S4670.json │ │ │ ├── S5362.html │ │ │ ├── S5362.json │ │ │ └── Sonar_way_profile.json │ │ │ └── stylelint │ │ │ └── rules.json │ │ └── static │ │ └── documentation.md │ ├── sonarcss-assembly.xml │ └── test │ ├── java │ └── org │ │ └── sonar │ │ └── css │ │ └── plugin │ │ ├── CssLanguageTest.java │ │ ├── CssPluginTest.java │ │ ├── CssRuleSensorTest.java │ │ ├── CssRulesDefinitionTest.java │ │ ├── MinifiedFilesFilterTest.java │ │ ├── SonarWayProfileTest.java │ │ ├── StylelintReportSensorTest.java │ │ ├── TestActiveRules.java │ │ ├── metrics │ │ ├── MetricSensorTest.java │ │ └── TokenizerTest.java │ │ ├── rules │ │ └── CssRuleTest.java │ │ └── server │ │ ├── CssAnalyzerBridgeServerTest.java │ │ ├── NetUtilsTest.java │ │ ├── NodeDeprecationWarningTest.java │ │ └── bundle │ │ ├── CssAnalyzerBundleTest.java │ │ └── ZipTest.java │ └── resources │ ├── bundle │ ├── invalid-zip-file.zip │ └── test-css-bundle.zip │ ├── mock-start-server │ ├── failedClose.js │ ├── startServer.js │ ├── testLogs.js │ └── throw.js │ └── stylelint-report │ ├── file.css │ ├── invalid-file.json │ ├── report-utf16.json │ ├── report-utf8-bom.json │ └── report.json ├── sonarpedia.json ├── third-party-licenses.sh ├── wss-unified-agent.config └── yarn.lock /.cirrus.star: -------------------------------------------------------------------------------- 1 | load("github.com/SonarSource/cirrus-modules@v2", "load_features") 2 | 3 | def main(ctx): 4 | return load_features(ctx) 5 | -------------------------------------------------------------------------------- /.cirrus/nodejs-10.Dockerfile: -------------------------------------------------------------------------------- 1 | ARG CIRRUS_AWS_ACCOUNT=275878209202 2 | FROM ${CIRRUS_AWS_ACCOUNT}.dkr.ecr.eu-central-1.amazonaws.com/base:j11-latest 3 | 4 | USER root 5 | 6 | ENV NODE_VERSION v10.23.2 7 | 8 | RUN wget -U "nodejs" -q -O nodejs.tar.gz https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-linux-x64.tar.gz \ 9 | && tar -xzf "nodejs.tar.gz" -C /usr/local --strip-components=1 --no-same-owner \ 10 | && rm nodejs.tar.gz \ 11 | && ln -s /usr/local/bin/node /usr/local/bin/nodejs 12 | 13 | ENV YARN_VERSION 1.22.5 14 | 15 | RUN curl -fsSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \ 16 | && mkdir -p /opt \ 17 | && tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/ \ 18 | && ln -s /opt/yarn-v$YARN_VERSION/bin/yarn /usr/local/bin/yarn \ 19 | && ln -s /opt/yarn-v$YARN_VERSION/bin/yarnpkg /usr/local/bin/yarnpkg \ 20 | && rm yarn-v$YARN_VERSION.tar.gz 21 | 22 | 23 | USER sonarsource 24 | -------------------------------------------------------------------------------- /.cirrus/nodejs-10.jdk17.Dockerfile: -------------------------------------------------------------------------------- 1 | ARG CIRRUS_AWS_ACCOUNT=275878209202 2 | FROM ${CIRRUS_AWS_ACCOUNT}.dkr.ecr.eu-central-1.amazonaws.com/base:j17-latest 3 | 4 | USER root 5 | 6 | ENV NODE_VERSION v10.23.2 7 | 8 | RUN wget -U "nodejs" -q -O nodejs.tar.gz https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-linux-x64.tar.gz \ 9 | && tar -xzf "nodejs.tar.gz" -C /usr/local --strip-components=1 --no-same-owner \ 10 | && rm nodejs.tar.gz \ 11 | && ln -s /usr/local/bin/node /usr/local/bin/nodejs 12 | 13 | ENV YARN_VERSION 1.22.5 14 | 15 | RUN curl -fsSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \ 16 | && mkdir -p /opt \ 17 | && tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/ \ 18 | && ln -s /opt/yarn-v$YARN_VERSION/bin/yarn /usr/local/bin/yarn \ 19 | && ln -s /opt/yarn-v$YARN_VERSION/bin/yarnpkg /usr/local/bin/yarnpkg \ 20 | && rm yarn-v$YARN_VERSION.tar.gz 21 | 22 | 23 | USER sonarsource 24 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | .github/CODEOWNERS @SonarSource/languages-team-jsts 2 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: sonar-release 3 | # This workflow is triggered when publishing a new github release 4 | # yamllint disable-line rule:truthy 5 | on: 6 | release: 7 | types: 8 | - published 9 | 10 | jobs: 11 | release: 12 | permissions: 13 | id-token: write 14 | contents: write 15 | uses: SonarSource/gh-action_release/.github/workflows/main.yaml@v5 16 | with: 17 | publishToBinaries: true 18 | mavenCentralSync: true 19 | slackChannel: team-lang-js-ts-css 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ---- Mac OS X 2 | .DS_Store 3 | Icon? 4 | # Thumbnails 5 | ._* 6 | # Files that might appear on external disk 7 | .Spotlight-V100 8 | .Trashes 9 | 10 | # ---- Windows 11 | # Windows image file caches 12 | Thumbs.db 13 | # Folder config file 14 | Desktop.ini 15 | 16 | # ---- IntelliJ IDEA 17 | *.iws 18 | *.iml 19 | *.ipr 20 | .idea/ 21 | out/ 22 | 23 | # ---- Eclipse 24 | .project 25 | .settings/ 26 | .classpath 27 | 28 | # --- SonarQube 29 | .sonar/ 30 | .sonarlint/ 31 | .scannerwork/ 32 | 33 | # --- Gradle 34 | .gradle/ 35 | build/ 36 | 37 | # --- Maven and Orchestrator 38 | target/ 39 | 40 | # npm 41 | node_modules/ 42 | 43 | # Visual Studio 44 | .vs/ 45 | 46 | # CSS-bundle 47 | sonar-css-plugin/css-bundle/test-report.xml 48 | sonar-css-plugin/css-bundle/coverage/ 49 | sonar-css-plugin/css-bundle/lib/ 50 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "its/sources/projects"] 2 | path = its/sources/projects 3 | url = https://github.com/SonarSource/css-test-sources.git 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DEPRECATED 2 | This project is deprecated. Now analysis for CSS code is provided by [SonarJS](https://github.com/SonarSource/SonarJS) analyzer. 3 | ## Code Quality and Security for CSS 4 | 5 | ### Building 6 | 7 | ```bash 8 | mvn package 9 | ``` 10 | 11 | ### Feedback 12 | Please use https://community.sonarsource.com/ to provide any kind of feedback about CSS analysis in SonarQube/SonarCloud/SonarLint. 13 | ### License 14 | 15 | Copyright 2018-2021 SonarSource. 16 | 17 | Licensed under the [GNU Lesser General Public License, Version 3.0](http://www.gnu.org/licenses/lgpl.txt) 18 | -------------------------------------------------------------------------------- /its/plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | its 7 | org.sonarsource.css 8 | 1.4.3-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | plugin 13 | 14 | 15 | 16 | 17 | maven-surefire-plugin 18 | 19 | 20 | **/Tests.java 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | org.sonarsource.orchestrator 30 | sonar-orchestrator 31 | 32 | 33 | org.sonarsource.sonarqube 34 | sonar-ws 35 | ${sonar.version} 36 | test 37 | 38 | 39 | org.assertj 40 | assertj-core 41 | 42 | 43 | org.sonarsource.css 44 | sonar-css-plugin 45 | ${version} 46 | test 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /its/plugin/projects/(dir with paren)/src/file1.css: -------------------------------------------------------------------------------- 1 | @import "a.css"; 2 | @import "a.css"; /* S1128 | no-duplicate-at-import-rules */ 3 | -------------------------------------------------------------------------------- /its/plugin/projects/external-report-project/report.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "source": "src/file1.css", 4 | "deprecations": [], 5 | "invalidOptionWarnings": [], 6 | "parseErrors": [], 7 | "errored": true, 8 | "warnings": [ 9 | { 10 | "line": 111, 11 | "column": 1, 12 | "rule": "no-missing-end-of-source-newline", 13 | "severity": "error", 14 | "text": "Unexpected missing end-of-source newline (no-missing-end-of-source-newline)" 15 | }, 16 | { 17 | "line": 81, 18 | "column": 1, 19 | "rule": "rule-empty-line-before", 20 | "severity": "error", 21 | "text": "Expected empty line before rule (rule-empty-line-before)" 22 | }, 23 | { 24 | "line": 55, 25 | "column": 20, 26 | "rule": "selector-pseudo-element-colon-notation", 27 | "severity": "error", 28 | "text": "Expected double colon pseudo-element notation (selector-pseudo-element-colon-notation)" 29 | } 30 | ] 31 | }, 32 | { 33 | "source": "src/file2.css", 34 | "deprecations": [], 35 | "invalidOptionWarnings": [], 36 | "parseErrors": [], 37 | "errored": true, 38 | "warnings": [ 39 | { 40 | "line": 58, 41 | "column": 28, 42 | "rule": "block-no-empty", 43 | "severity": "error", 44 | "text": "Unexpected empty block (block-no-empty)" 45 | }, 46 | { 47 | "line": 114, 48 | "column": 1, 49 | "rule": "no-missing-end-of-source-newline", 50 | "severity": "error", 51 | "text": "Unexpected missing end-of-source newline (no-missing-end-of-source-newline)" 52 | } 53 | ] 54 | } 55 | ] 56 | -------------------------------------------------------------------------------- /its/plugin/projects/external-report-project/src/file1.css: -------------------------------------------------------------------------------- 1 | .navbar-search { 2 | position: relative; 3 | padding: calc((var(--globalNavHeight) - var(--globalNavContentHeight)) / 2) 0; 4 | } 5 | 6 | .navbar-search .search-box, 7 | .navbar-search .search-box-input { 8 | width: 26vw; 9 | max-width: 310px; 10 | min-width: 260px; 11 | height: var(--globalNavContentHeight); 12 | } 13 | 14 | .navbar-search .search-box-input { 15 | border-color: #fff; 16 | } 17 | 18 | .navbar-search .search-box-note { 19 | line-height: calc(var(--globalNavContentHeight) - 2px); 20 | } 21 | 22 | .navbar-search .search-box-magnifier, 23 | .navbar-search .search-box-clear { 24 | top: calc((var(--globalNavContentHeight) - 16px) / 2); 25 | } 26 | 27 | .navbar-search-input { 28 | vertical-align: middle; 29 | width: 310px; 30 | margin-top: 3px; 31 | margin-bottom: 3px; 32 | padding-left: 26px !important; 33 | } 34 | 35 | .navbar-search-input-hint { 36 | position: absolute; 37 | top: 1px; 38 | right: 27px; 39 | line-height: var(--controlHeight); 40 | font-size: var(--smallFontSize); 41 | color: var(--secondFontColor); 42 | } 43 | 44 | .navbar-search-icon { 45 | position: relative; 46 | z-index: var(--aboveNormalZIndex); 47 | vertical-align: middle; 48 | width: 16px; 49 | margin-left: 4px; 50 | margin-right: -20px; 51 | background-color: #fff; 52 | color: var(--secondFontColor); 53 | } 54 | 55 | .navbar-search-icon:before { 56 | font-size: var(--mediumFontSize); 57 | } 58 | 59 | .navbar-search-item-link { 60 | display: flex !important; 61 | } 62 | 63 | .navbar-search-item-match { 64 | flex-grow: 5; 65 | overflow: hidden; 66 | text-overflow: ellipsis; 67 | } 68 | 69 | .navbar-search-item-right { 70 | flex-grow: 1; 71 | padding-left: 10px; 72 | text-align: right; 73 | } 74 | 75 | .navbar-search-item-icons { 76 | position: relative; 77 | flex-shrink: 0; 78 | width: 16px; 79 | height: 16px; 80 | } 81 | .navbar-search-item-icons > * { 82 | position: absolute; 83 | z-index: 5; 84 | top: 0; 85 | left: 0; 86 | } 87 | 88 | .navbar-search-item-icons > .icon-outline, 89 | .navbar-search-item-icons > .icon-clock { 90 | z-index: 6; 91 | top: -4px; 92 | left: -5px; 93 | } 94 | 95 | .navbar-search-no-results { 96 | margin-top: 4px; 97 | padding: 5px 10px; 98 | } 99 | 100 | .global-navbar-search-dropdown { 101 | top: 100% !important; 102 | max-height: 80vh; 103 | width: 440px; 104 | padding: 0 !important; 105 | overflow-y: auto; 106 | overflow-x: hidden; 107 | } 108 | 109 | .global-navbar-search-dropdown .dropdown-bottom-hint { 110 | margin-bottom: 0; 111 | } -------------------------------------------------------------------------------- /its/plugin/projects/external-report-project/src/file2.css: -------------------------------------------------------------------------------- 1 | .date-input-control { 2 | position: relative; 3 | display: inline-block; 4 | cursor: pointer; 5 | } 6 | 7 | .date-input-control-input { 8 | width: 130px; 9 | padding-left: var(--controlHeight) !important; 10 | cursor: pointer; 11 | } 12 | 13 | .date-input-control-input.is-filled { 14 | padding-right: 16px !important; 15 | } 16 | 17 | .date-input-control-icon { 18 | position: absolute; 19 | top: 4px; 20 | left: 4px; 21 | } 22 | 23 | .date-input-control-icon path { 24 | fill: var(--gray80); 25 | transition: fill 0.3s ease; 26 | } 27 | 28 | .date-input-control-input:focus + .date-input-control-icon path { 29 | fill: var(--blue); 30 | } 31 | 32 | .date-input-control-reset { 33 | position: absolute; 34 | top: 4px; 35 | right: 4px; 36 | border: none; 37 | } 38 | 39 | .date-input-calendar { 40 | position: absolute; 41 | z-index: var(--dropdownMenuZIndex); 42 | top: 100%; 43 | left: 0; 44 | border: 1px solid var(--barBorderColor); 45 | background-color: #fff; 46 | box-shadow: var(--defaultShadow); 47 | } 48 | 49 | .date-input-calendar-nav { 50 | display: flex; 51 | justify-content: space-between; 52 | align-items: center; 53 | padding-top: var(--gridSize); 54 | padding-left: var(--gridSize); 55 | padding-right: var(--gridSize); 56 | } 57 | 58 | .date-input-calender-month { 59 | } 60 | 61 | .date-input-calender-month-select { 62 | width: 70px; 63 | } 64 | 65 | .button.boolean-toggle { 66 | display: inline-block; 67 | vertical-align: middle; 68 | width: 48px; 69 | height: var(--controlHeight); 70 | padding: 1px; 71 | border: 1px solid var(--gray80); 72 | border-radius: var(--controlHeight); 73 | box-sizing: border-box; 74 | background-color: #fff; 75 | cursor: pointer; 76 | transition: all 0.3s ease; 77 | } 78 | 79 | .button.boolean-toggle:hover { 80 | background-color: #fff; 81 | } 82 | 83 | .button.boolean-toggle:focus { 84 | border-color: var(--blue); 85 | background-color: #f6f6f6; 86 | } 87 | 88 | .boolean-toggle-handle { 89 | width: 20px; 90 | height: 20px; 91 | border: 1px solid var(--gray80); 92 | border-radius: 22px; 93 | box-sizing: border-box; 94 | background-color: #f6f6f6; 95 | transition: transform 0.3s cubic-bezier(0.87, -0.41, 0.19, 1.44), border 0.3s ease; 96 | } 97 | 98 | .button.boolean-toggle-on { 99 | border-color: var(--darkBlue); 100 | background-color: var(--darkBlue); 101 | } 102 | 103 | .button.boolean-toggle-on:hover { 104 | background-color: var(--darkBlue); 105 | } 106 | 107 | .button.boolean-toggle-on:focus { 108 | background-color: var(--darkBlue); 109 | } 110 | 111 | .button.boolean-toggle-on .boolean-toggle-handle { 112 | border-color: #f6f6f6; 113 | transform: translateX(var(--controlHeight)); 114 | } -------------------------------------------------------------------------------- /its/plugin/projects/issues-project/src/cssModules.css: -------------------------------------------------------------------------------- 1 | /* Adding one standard issue to make sure we analyze this file */ 2 | @unknown { /* S4662 | at-rule-no-unknown */ 3 | width: 1px; 4 | } 5 | 6 | /* ignored by S4662 | at-rule-no-unknown */ 7 | @value colors: "./colors.css"; 8 | @value blue, red, green from colors; 9 | 10 | .className { 11 | color: green; 12 | background: red; 13 | } 14 | .otherClassName { 15 | /* ignored by S4654 | property-no-unknown */ 16 | composes: className; 17 | color: yellow; 18 | } 19 | 20 | /* ignored by S4659 | selector-pseudo-class-no-unknown */ 21 | :export { 22 | /* ignored by S4654 | property-no-unknown */ 23 | exportedKey: exportedValue; 24 | /* ... */ 25 | } 26 | 27 | /* ignored by S4659 | selector-pseudo-class-no-unknown */ 28 | :import("path/to/dep.css") { 29 | /* ignored by S4654 | property-no-unknown */ 30 | localAlias: keyFromDep; 31 | /* ... */ 32 | } 33 | -------------------------------------------------------------------------------- /its/plugin/projects/issues-project/src/empty1.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonarSource/sonar-css/0885b299dc850766eae254cebc6d8de85f4957ab/its/plugin/projects/issues-project/src/empty1.css -------------------------------------------------------------------------------- /its/plugin/projects/issues-project/src/empty2.less: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonarSource/sonar-css/0885b299dc850766eae254cebc6d8de85f4957ab/its/plugin/projects/issues-project/src/empty2.less -------------------------------------------------------------------------------- /its/plugin/projects/issues-project/src/empty3.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonarSource/sonar-css/0885b299dc850766eae254cebc6d8de85f4957ab/its/plugin/projects/issues-project/src/empty3.scss -------------------------------------------------------------------------------- /its/plugin/projects/issues-project/src/file-with-parsing-error-excluded.css: -------------------------------------------------------------------------------- 1 | a { 2 | -------------------------------------------------------------------------------- /its/plugin/projects/issues-project/src/file-with-parsing-error.css: -------------------------------------------------------------------------------- 1 | a { 2 | -------------------------------------------------------------------------------- /its/plugin/projects/issues-project/src/file-with-parsing-error.less: -------------------------------------------------------------------------------- 1 | .foo(@i : 1 ) when (@i <= 10){ 2 | @num : @i *10 ; 3 | .height-@{num}{ 4 | height : @num * 1%; 5 | } 6 | } 7 | 8 | -------------------------------------------------------------------------------- /its/plugin/projects/issues-project/src/file2.less: -------------------------------------------------------------------------------- 1 | @import "a.css"; 2 | @import "a.css"; /* S1128 | no-duplicate-at-import-rules */ 3 | 4 | b a { 5 | color: pink;; /* S1116 | no-extra-semicolons */ 6 | } 7 | 8 | a { /* S4664 | no-descending-specificity */ 9 | color: red; 10 | } 11 | 12 | a::pseudo { /* S4660 | selector-pseudo-element-no-unknown */ 13 | color: red; 14 | } 15 | 16 | a:unknown { /* S4659 | selector-pseudo-class-no-unknown */ 17 | background-color: #ffw; /* S4647 | color-no-invalid-hex */ 18 | /* */ /* S4663 | comment-no-empty */ 19 | content: "first 20 | second"; /* S4652 | string-no-newline */ 21 | color: pink; 22 | color: pink; /* S4656 | declaration-block-no-duplicate-properties */ 23 | color: orange; /* S4656 | declaration-block-no-duplicate-properties | Not raised because property has a different value */ 24 | font: 1em/1.3 Times; /* S4649 | font-family-no-missing-generic-family-keyword */ 25 | font-family: serif, serif; /* S4648 | font-family-no-duplicate-names */ 26 | heigth: 100%; /* S4654 | property-no-unknown */ 27 | padding-left: 10px; 28 | padding: 20px; /* S4657 | declaration-block-no-shorthand-property-overrides */ 29 | top: calc(1px+2px); /* S4650 | function-calc-no-unspaced-operator */ /* S4653 | unit-no-unknown */ 30 | width: calc(100% 80px); /* S5362 | function-calc-no-invalid */ 31 | } 32 | 33 | // color: pink; /* S4668 | no-invalid-double-slash-comments | Doesn't raise for LESS */ 34 | 35 | .class1 { 36 | width: 100px; 37 | background: linear-gradient(top, #fff, #000); /* S4651 | function-linear-gradient-no-nonstandard-direction */ 38 | } 39 | 40 | .class1 { /* S4666 | no-duplicate-selectors */ 41 | padding: 100px; 42 | } 43 | 44 | unknown { /* S4670 | selector-type-no-unknown */ 45 | color: black; 46 | } 47 | 48 | @unknown { /* S4662 | at-rule-no-unknown */ 49 | width: 1px; 50 | } 51 | 52 | @keyframes important1 { 53 | from { 54 | margin-top: 50px; 55 | } 56 | to { 57 | margin-top: 100px !important; /* S4655 | keyframe-declaration-no-important */ 58 | } 59 | } 60 | 61 | .class2 { } /* S4658 | block-no-empty */ 62 | 63 | @media screen and (unknown) { /* S4661 | media-feature-name-no-unknown */ 64 | width: 2px; 65 | } 66 | -------------------------------------------------------------------------------- /its/plugin/projects/issues-project/src/file3.scss: -------------------------------------------------------------------------------- 1 | @import "a.css"; 2 | @import "a.css"; /* S1128 | no-duplicate-at-import-rules */ 3 | 4 | b a { 5 | color: pink;; /* S1116 | no-extra-semicolons */ 6 | } 7 | 8 | a { /* S4664 | no-descending-specificity */ 9 | color: red; 10 | } 11 | 12 | a::pseudo { /* S4660 | selector-pseudo-element-no-unknown */ 13 | color: red; 14 | } 15 | 16 | a:unknown { /* S4659 | selector-pseudo-class-no-unknown */ 17 | background-color: #ffw; /* S4647 | color-no-invalid-hex */ 18 | /* */ /* S4663 | comment-no-empty */ 19 | content: "first 20 | second"; /* S4652 | string-no-newline */ 21 | color: pink; 22 | color: pink; /* S4656 | declaration-block-no-duplicate-properties */ 23 | color: orange; /* S4656 | declaration-block-no-duplicate-properties | Not raised because property has a different value */ 24 | font: 1em/1.3 Times; /* S4649 | font-family-no-missing-generic-family-keyword */ 25 | font-family: serif, serif; /* S4648 | font-family-no-duplicate-names */ 26 | heigth: 100%; /* S4654 | property-no-unknown */ 27 | padding-left: 10px; 28 | padding: 20px; /* S4657 | declaration-block-no-shorthand-property-overrides */ 29 | top: calc(1px+2px); /* S4650 | function-calc-no-unspaced-operator */ /* S4653 | unit-no-unknown */ 30 | width: calc(100% 80px); /* S5362 | function-calc-no-invalid */ 31 | } 32 | 33 | // color: pink; /* S4668 | no-invalid-double-slash-comments | Doesn't raise for SCSS */ 34 | 35 | .class1 { 36 | width: 100px; 37 | background: linear-gradient(top, #fff, #000); /* S4651 | function-linear-gradient-no-nonstandard-direction */ 38 | } 39 | 40 | .class1 { /* S4666 | no-duplicate-selectors */ 41 | padding: 100px; 42 | } 43 | 44 | unknown { /* S4670 | selector-type-no-unknown */ 45 | color: black; 46 | } 47 | 48 | @unknown { /* S4662 | at-rule-no-unknown */ 49 | width: 1px; 50 | } 51 | 52 | @keyframes important1 { 53 | from { 54 | margin-top: 50px; 55 | } 56 | to { 57 | margin-top: 100px !important; /* S4655 | keyframe-declaration-no-important */ 58 | } 59 | } 60 | 61 | .class2 { } /* S4658 | block-no-empty */ 62 | 63 | @media screen and (unknown) { /* S4661 | media-feature-name-no-unknown */ 64 | width: 2px; 65 | } 66 | 67 | @mixin adjust-location($x, $y) { 68 | @if unitless($x) { 69 | color: blue; 70 | @debug ""; 71 | @warn ""; 72 | @error ""; 73 | @at-root [dir="ltr"] { color: blue; } 74 | } @else { 75 | color: black; 76 | } 77 | } 78 | 79 | @for $i from 1 through 3 { 80 | .item-#{$i} { width: 2em * $i; } 81 | } 82 | 83 | @each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) { 84 | #{$header} { 85 | font-size: $size; 86 | @include large-text; 87 | } 88 | } 89 | 90 | $i: 6; 91 | @while $i > 0 { 92 | .item-#{$i} { width: 2em * $i; } 93 | $i: $i - 2; 94 | } 95 | -------------------------------------------------------------------------------- /its/plugin/projects/issues-project/src/file4.foo: -------------------------------------------------------------------------------- 1 | File required to test execution of analysis on a file with non-css extension 2 | -------------------------------------------------------------------------------- /its/plugin/projects/issues-project/src/file5-1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Title 6 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /its/plugin/projects/issues-project/src/file5.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Page Title 5 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /its/plugin/projects/issues-project/src/file6.vue: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 13 | -------------------------------------------------------------------------------- /its/plugin/projects/issues-project/src/file7.jsx: -------------------------------------------------------------------------------- 1 | // file is not analyzed 2 | -------------------------------------------------------------------------------- /its/plugin/projects/metrics-project/src/file1.css: -------------------------------------------------------------------------------- 1 | .class1 { 2 | background-color: #2d5e8b; 3 | } 4 | .class1 .class2 { 5 | color: #2d5e8b; 6 | foo: "some text"; 7 | } 8 | 9 | /* some comment */ -------------------------------------------------------------------------------- /its/plugin/projects/metrics-project/src/file2.less: -------------------------------------------------------------------------------- 1 | @color-base: #2d5e8b; 2 | .class1 { 3 | background-color: @color-base; 4 | .class2 { 5 | background-color: #fff; 6 | color: @color-base; 7 | foo: "some text"; 8 | } 9 | } 10 | 11 | /* some comment */ -------------------------------------------------------------------------------- /its/plugin/projects/metrics-project/src/file3.scss: -------------------------------------------------------------------------------- 1 | $firstValue: 62.5%; 2 | 3 | $firstValue: 24px !default; 4 | 5 | body { 6 | font-size: $firstValue; 7 | foo: "some text"; 8 | } 9 | 10 | // body font size = 62.5% 11 | 12 | /* some comment */ -------------------------------------------------------------------------------- /its/plugin/projects/metrics-project/src/file4.html: -------------------------------------------------------------------------------- 1 | 2 | Example 3 | 10 |

Hello World!

11 | -------------------------------------------------------------------------------- /its/plugin/projects/minified-project/src/normal.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: red; 3 | } 4 | -------------------------------------------------------------------------------- /its/plugin/projects/minified-project/src/normal.min.css: -------------------------------------------------------------------------------- 1 | /* content doesn't matter as file excluded based on filename */ 2 | body { 3 | color: red; 4 | } 5 | -------------------------------------------------------------------------------- /its/plugin/projects/minified-project/src/oneline.css: -------------------------------------------------------------------------------- 1 | /* Styles */ @import url(extra.css);ul li{list-style:square;margin:2em 20% 15px 0}#content{-webkit-font-smoothing:antialiased;background:url(img/gradient.png);background:linear-gradient(to bottom,red,rgba(255,0,0,0))}@media only screen and (min-width:35em){#content{width:50%}}.item+.item,.item~.item{margin-left:-15px}#buttons .lotsofcontent,#buttons>*,input[type=submit]{border-radius:.3rem}a:focus,a:hover{color:green}blockquote::after,blockquote::before{content:"\201d"} 2 | -------------------------------------------------------------------------------- /its/plugin/projects/php-project/src/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Index 5 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /its/plugin/src/test/java/org/sonar/css/its/MetricsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.its; 21 | 22 | import com.sonar.orchestrator.Orchestrator; 23 | import org.junit.BeforeClass; 24 | import org.junit.ClassRule; 25 | import org.junit.Test; 26 | 27 | import static org.assertj.core.api.Assertions.assertThat; 28 | import static org.sonar.css.its.Tests.getMeasure; 29 | import static org.sonar.css.its.Tests.getProjectMeasureAsDouble; 30 | 31 | public class MetricsTest { 32 | 33 | private static String PROJECT_KEY = "metrics-project"; 34 | 35 | @ClassRule 36 | public static Orchestrator orchestrator = Tests.ORCHESTRATOR; 37 | 38 | @BeforeClass 39 | public static void prepare() { 40 | orchestrator.executeBuild(Tests.createScanner(PROJECT_KEY)); 41 | } 42 | 43 | @Test 44 | public void test() { 45 | assertThat(getProjectMeasureAsDouble("lines", PROJECT_KEY)).isEqualTo(43); 46 | assertThat(getProjectMeasureAsDouble("ncloc", PROJECT_KEY)).isEqualTo(32); 47 | assertThat(getMeasure("ncloc_language_distribution", PROJECT_KEY).getValue()).isEqualTo("css=22;web=10"); 48 | assertThat(getProjectMeasureAsDouble("comment_lines", PROJECT_KEY)).isEqualTo(4); 49 | 50 | assertThat(getMeasure("ncloc_data", PROJECT_KEY + ":src/file1.css").getValue()) 51 | .contains("1=1;", "2=1;", "3=1;", "4=1;", "5=1;", "6=1;", "7=1"); 52 | 53 | assertThat(getMeasure("ncloc_data", PROJECT_KEY + ":src/file2.less").getValue()) 54 | .contains("1=1;", "2=1;", "3=1;", "4=1;", "5=1;", "6=1;", "7=1;", "8=1;", "9=1"); 55 | 56 | assertThat(getMeasure("ncloc_data", PROJECT_KEY + ":src/file3.scss").getValue()) 57 | .contains("1=1;", "3=1;", "5=1;", "6=1;", "7=1;", "8=1"); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /its/plugin/src/test/java/org/sonar/css/its/MinifiedTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.its; 21 | 22 | import com.sonar.orchestrator.Orchestrator; 23 | import org.junit.BeforeClass; 24 | import org.junit.ClassRule; 25 | import org.junit.Test; 26 | 27 | import static org.assertj.core.api.Assertions.assertThat; 28 | import static org.sonar.css.its.Tests.getProjectMeasureAsDouble; 29 | 30 | public class MinifiedTest { 31 | 32 | private static String PROJECT_KEY = "minified-project"; 33 | 34 | @ClassRule 35 | public static Orchestrator orchestrator = Tests.ORCHESTRATOR; 36 | 37 | @BeforeClass 38 | public static void prepare() { 39 | orchestrator.executeBuild(Tests.createScanner(PROJECT_KEY)); 40 | } 41 | 42 | @Test 43 | public void test() { 44 | assertThat(getProjectMeasureAsDouble("files", PROJECT_KEY)).isEqualTo(1); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /its/plugin/src/test/java/org/sonar/css/its/NoCssFileProjectTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.its; 21 | 22 | import com.sonar.orchestrator.Orchestrator; 23 | import com.sonar.orchestrator.build.SonarScanner; 24 | import java.util.Collections; 25 | import java.util.List; 26 | import java.util.stream.Collectors; 27 | import org.junit.BeforeClass; 28 | import org.junit.ClassRule; 29 | import org.junit.Test; 30 | import org.sonarqube.ws.Issues; 31 | import org.sonarqube.ws.client.issues.SearchRequest; 32 | 33 | import static org.assertj.core.api.Assertions.assertThat; 34 | import static org.assertj.core.api.Assertions.tuple; 35 | import static org.sonar.css.its.Tests.newWsClient; 36 | 37 | public class NoCssFileProjectTest { 38 | 39 | private static String PROJECT_KEY = "php-project"; 40 | 41 | @ClassRule 42 | public static Orchestrator orchestrator = Tests.ORCHESTRATOR; 43 | 44 | @BeforeClass 45 | public static void prepare() { 46 | orchestrator.getServer().provisionProject(PROJECT_KEY, PROJECT_KEY); 47 | SonarScanner scanner = Tests.createScanner(PROJECT_KEY); 48 | orchestrator.executeBuild(scanner); 49 | } 50 | 51 | @Test 52 | public void test() { 53 | SearchRequest request = new SearchRequest(); 54 | request.setComponentKeys(Collections.singletonList(PROJECT_KEY)); 55 | List issuesList = newWsClient().issues().search(request).getIssuesList().stream() 56 | .filter(i -> i.getRule().startsWith("css:")) 57 | .collect(Collectors.toList()); 58 | 59 | assertThat(issuesList).extracting(Issues.Issue::getRule, Issues.Issue::getLine, Issues.Issue::getComponent).containsExactlyInAnyOrder( 60 | tuple("css:S4658", 7, "php-project:src/index.php")); 61 | 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /its/plugin/src/test/java/org/sonar/css/its/NonStandardPathTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.its; 21 | 22 | import com.sonar.orchestrator.Orchestrator; 23 | import com.sonar.orchestrator.build.SonarScanner; 24 | import com.sonar.orchestrator.locator.FileLocation; 25 | import java.io.File; 26 | import java.util.Collections; 27 | import java.util.List; 28 | import java.util.stream.Collectors; 29 | import org.junit.BeforeClass; 30 | import org.junit.ClassRule; 31 | import org.junit.Test; 32 | import org.sonarqube.ws.Issues.Issue; 33 | import org.sonarqube.ws.client.issues.SearchRequest; 34 | import org.sonarsource.analyzer.commons.ProfileGenerator; 35 | import org.sonarsource.analyzer.commons.ProfileGenerator.RulesConfiguration; 36 | 37 | import static org.assertj.core.api.Assertions.assertThat; 38 | import static org.assertj.core.api.Assertions.tuple; 39 | import static org.sonar.css.its.Tests.newWsClient; 40 | 41 | public class NonStandardPathTest { 42 | 43 | private static String PROJECT_KEY = "dir-with-paren"; 44 | 45 | @ClassRule 46 | public static Orchestrator orchestrator = Tests.ORCHESTRATOR; 47 | 48 | @BeforeClass 49 | public static void prepare() { 50 | RulesConfiguration rulesConfiguration = new RulesConfiguration(); 51 | File profile = ProfileGenerator.generateProfile(orchestrator.getServer().getUrl(), "css", "css", rulesConfiguration, Collections.emptySet()); 52 | orchestrator.getServer().restoreProfile(FileLocation.of(profile)); 53 | 54 | orchestrator.getServer().provisionProject(PROJECT_KEY, PROJECT_KEY); 55 | orchestrator.getServer().associateProjectToQualityProfile(PROJECT_KEY, "css", "rules"); 56 | 57 | File projectDir = FileLocation.of("projects" + File.separator + "(dir with paren)").getFile(); 58 | SonarScanner scanner = Tests.createScanner(PROJECT_KEY, projectDir); 59 | orchestrator.executeBuild(scanner); 60 | } 61 | 62 | @Test 63 | public void test() { 64 | SearchRequest request = new SearchRequest(); 65 | request.setComponentKeys(Collections.singletonList(PROJECT_KEY)); 66 | List issuesList = newWsClient().issues().search(request).getIssuesList().stream() 67 | .filter(i -> i.getRule().startsWith("css:")) 68 | .collect(Collectors.toList()); 69 | 70 | assertThat(issuesList).extracting(Issue::getRule, Issue::getComponent).containsExactly( 71 | tuple("css:S1128", "dir-with-paren:src/file1.css") 72 | ); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /its/plugin/src/test/java/org/sonar/css/its/StylelintReportTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.its; 21 | 22 | import com.sonar.orchestrator.Orchestrator; 23 | import java.util.Collections; 24 | import java.util.List; 25 | import org.junit.BeforeClass; 26 | import org.junit.ClassRule; 27 | import org.junit.Test; 28 | import org.sonarqube.ws.Issues.Issue; 29 | import org.sonarqube.ws.client.issues.SearchRequest; 30 | 31 | import static org.assertj.core.api.Assertions.assertThat; 32 | import static org.sonar.css.its.Tests.newWsClient; 33 | 34 | public class StylelintReportTest { 35 | 36 | private static String PROJECT_KEY = "external-report-project"; 37 | 38 | @ClassRule 39 | public static Orchestrator orchestrator = Tests.ORCHESTRATOR; 40 | 41 | @BeforeClass 42 | public static void prepare() { 43 | orchestrator.executeBuild(Tests.createScanner(PROJECT_KEY).setProperty("sonar.css.stylelint.reportPaths", "report.json")); 44 | } 45 | 46 | @Test 47 | public void test() { 48 | if (orchestrator.getServer().version().isGreaterThanOrEquals(7, 2)) { 49 | SearchRequest request = new SearchRequest(); 50 | request.setComponentKeys(Collections.singletonList(PROJECT_KEY)); 51 | List issuesList = newWsClient().issues().search(request).getIssuesList(); 52 | 53 | assertThat(issuesList).extracting("line").containsExactlyInAnyOrder(111, 81, 55, 58, 114); 54 | assertThat(issuesList).extracting("rule").containsExactlyInAnyOrder( 55 | "external_stylelint:no-missing-end-of-source-newline", 56 | "external_stylelint:no-missing-end-of-source-newline", 57 | "external_stylelint:rule-empty-line-before", 58 | "external_stylelint:selector-pseudo-element-colon-notation", 59 | "css:S4658"); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /its/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | css 7 | org.sonarsource.css 8 | 1.4.3-SNAPSHOT 9 | 10 | 11 | 4.0.0 12 | 13 | its 14 | pom 15 | 16 | 17 | plugin 18 | ruling 19 | 20 | 21 | 22 | 23 | qa 24 | 25 | 26 | env.SONARSOURCE_QA 27 | true 28 | 29 | 30 | 31 | 32 | 33 | org.apache.maven.plugins 34 | maven-dependency-plugin 35 | 2.10 36 | 37 | 38 | copy-plugin 39 | generate-test-resources 40 | 41 | copy 42 | 43 | 44 | 45 | 46 | ${project.groupId} 47 | sonar-css-plugin 48 | ${project.version} 49 | sonar-plugin 50 | true 51 | 52 | 53 | ../../sonar-css-plugin/target 54 | true 55 | true 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /its/ruling/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | its 7 | org.sonarsource.css 8 | 1.4.3-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | ruling 13 | 14 | 15 | 16 | 17 | org.sonarsource.orchestrator 18 | sonar-orchestrator 19 | 20 | 21 | org.sonarsource.sonarqube 22 | sonar-ws 23 | ${sonar.version} 24 | test 25 | 26 | 27 | junit 28 | junit 29 | 30 | 31 | org.assertj 32 | assertj-core 33 | 34 | 35 | org.sonarsource.css 36 | sonar-css-plugin 37 | ${version} 38 | test 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /its/ruling/src/test/resources/expected/css-S4647.json: -------------------------------------------------------------------------------- 1 | { 2 | 'project:projects/bulma-0.9.2/docs/_includes/global/native.html':[ 3 | 45, 4 | 45, 5 | 45, 6 | 49, 7 | 53, 8 | 57, 9 | 58, 10 | 62, 11 | 63, 12 | ], 13 | } 14 | -------------------------------------------------------------------------------- /its/ruling/src/test/resources/expected/css-S4648.json: -------------------------------------------------------------------------------- 1 | { 2 | 'project:custom/test.css':[ 3 | 7, 4 | ], 5 | 'project:projects/normalize.css-8.0.1/normalize.css':[ 6 | 65, 7 | 108, 8 | ], 9 | } 10 | -------------------------------------------------------------------------------- /its/ruling/src/test/resources/expected/css-S4653.json: -------------------------------------------------------------------------------- 1 | { 2 | 'project:custom/S4653.scss':[ 3 | 4, 4 | 5, 5 | ], 6 | } 7 | -------------------------------------------------------------------------------- /its/ruling/src/test/resources/expected/css-S4654.json: -------------------------------------------------------------------------------- 1 | { 2 | 'project:custom/S4654.css':[ 3 | 2, 4 | ], 5 | 'project:custom/S4654.scss':[ 6 | 11, 7 | 12, 8 | 13, 9 | ], 10 | 'project:projects/bulma-0.9.2/docs/css/bulma-docs.css':[ 11 | 13084, 12 | 15716, 13 | ], 14 | } 15 | -------------------------------------------------------------------------------- /its/ruling/src/test/resources/expected/css-S4656.json: -------------------------------------------------------------------------------- 1 | { 2 | 'project:projects/animate.css-4.1.1/animate.css':[ 3 | 16, 4 | 28, 5 | 34, 6 | 40, 7 | 46, 8 | 52, 9 | 58, 10 | 64, 11 | 70, 12 | 76, 13 | 82, 14 | 88, 15 | 94, 16 | 861, 17 | 1296, 18 | 1655, 19 | 2792, 20 | 2838, 21 | 3370, 22 | ], 23 | 'project:projects/bulma-0.9.2/css/bulma-rtl.css':[ 24 | 1776, 25 | ], 26 | 'project:projects/bulma-0.9.2/css/bulma.css':[ 27 | 1776, 28 | ], 29 | 'project:projects/bulma-0.9.2/docs/css/bulma-docs.css':[ 30 | 1777, 31 | 13114, 32 | 13116, 33 | 13118, 34 | 15810, 35 | 15813, 36 | 15816, 37 | 15817, 38 | ], 39 | } 40 | -------------------------------------------------------------------------------- /its/ruling/src/test/resources/expected/css-S4658.json: -------------------------------------------------------------------------------- 1 | { 2 | 'project:custom/S4670.css':[ 3 | 1, 4 | 2, 5 | 3, 6 | ], 7 | } 8 | -------------------------------------------------------------------------------- /its/ruling/src/test/resources/expected/css-S4661.json: -------------------------------------------------------------------------------- 1 | { 2 | 'project:projects/animate.css-4.1.1/docs/style.css':[ 3 | 592, 4 | ], 5 | } 6 | -------------------------------------------------------------------------------- /its/ruling/src/test/resources/expected/css-S4662.json: -------------------------------------------------------------------------------- 1 | { 2 | 'project:projects/tailwindcss-2.0.3/__tests__/fixtures/tailwind-input-import.css':[ 3 | 7, 4 | ], 5 | 'project:projects/tailwindcss-2.0.3/__tests__/fixtures/tailwind-input-with-explicit-screen-utilities.css':[ 6 | 1, 7 | 7, 8 | ], 9 | 'project:projects/tailwindcss-2.0.3/__tests__/fixtures/tailwind-input.css':[ 10 | 1, 11 | 3, 12 | 5, 13 | 7, 14 | ], 15 | 'project:projects/tailwindcss-2.0.3/base.css':[ 16 | 1, 17 | ], 18 | 'project:projects/tailwindcss-2.0.3/components.css':[ 19 | 1, 20 | ], 21 | 'project:projects/tailwindcss-2.0.3/perf/fixture.css':[ 22 | 1, 23 | 3, 24 | 5, 25 | ], 26 | 'project:projects/tailwindcss-2.0.3/screens.css':[ 27 | 1, 28 | ], 29 | 'project:projects/tailwindcss-2.0.3/tailwind.css':[ 30 | 1, 31 | 3, 32 | 5, 33 | ], 34 | 'project:projects/tailwindcss-2.0.3/utilities.css':[ 35 | 1, 36 | ], 37 | } 38 | -------------------------------------------------------------------------------- /its/ruling/src/test/resources/expected/css-S4666.json: -------------------------------------------------------------------------------- 1 | { 2 | 'project:projects/animate.css-4.1.1/docs/style.css':[ 3 | 598, 4 | 602, 5 | ], 6 | 'project:projects/bulma-0.9.2/css/bulma-rtl.css':[ 7 | 304, 8 | ], 9 | 'project:projects/bulma-0.9.2/css/bulma.css':[ 10 | 304, 11 | ], 12 | 'project:projects/bulma-0.9.2/docs/css/bulma-docs.css':[ 13 | 305, 14 | 12108, 15 | 12114, 16 | 13821, 17 | 14283, 18 | 14354, 19 | 15992, 20 | 16007, 21 | 16014, 22 | 16029, 23 | 16034, 24 | 16085, 25 | 16090, 26 | 16095, 27 | 16175, 28 | 16182, 29 | 16189, 30 | 16258, 31 | 16265, 32 | ], 33 | 'project:projects/normalize.css-8.0.1/test.html':[ 34 | 50, 35 | ], 36 | 'project:projects/tailwindcss-2.0.3/__tests__/fixtures/tailwind-output-flagged.css':[ 37 | 56, 38 | 366, 39 | 376, 40 | 420, 41 | 453, 42 | 485, 43 | 502, 44 | 19542, 45 | ], 46 | 'project:projects/tailwindcss-2.0.3/__tests__/fixtures/tailwind-output-important.css':[ 47 | 56, 48 | 366, 49 | 376, 50 | 420, 51 | 453, 52 | 485, 53 | 502, 54 | 19542, 55 | ], 56 | 'project:projects/tailwindcss-2.0.3/__tests__/fixtures/tailwind-output-no-color-opacity.css':[ 57 | 56, 58 | 366, 59 | 376, 60 | 420, 61 | 453, 62 | 485, 63 | 502, 64 | 17696, 65 | ], 66 | 'project:projects/tailwindcss-2.0.3/__tests__/fixtures/tailwind-output.css':[ 67 | 56, 68 | 366, 69 | 376, 70 | 420, 71 | 453, 72 | 485, 73 | 502, 74 | 19542, 75 | ], 76 | } 77 | -------------------------------------------------------------------------------- /its/ruling/src/test/resources/expected/css-S4667.json: -------------------------------------------------------------------------------- 1 | { 2 | 'project:projects/normalize.css-8.0.1/test.html':[ 3 | 253, 4 | ], 5 | } 6 | -------------------------------------------------------------------------------- /its/ruling/src/test/resources/expected/css-S4670.json: -------------------------------------------------------------------------------- 1 | { 2 | 'project:custom/S4670.css':[ 3 | 1, 4 | 2, 5 | ], 6 | } 7 | -------------------------------------------------------------------------------- /its/sources/custom/S4653.scss: -------------------------------------------------------------------------------- 1 | $i: 1; 2 | 3 | .parent { 4 | width: $i/1.3+px; // FP (issue-160) 5 | height: $i/1.3+0px; // FP (issue-160) 6 | 7 | height: $i/1.3*1px; // this is OK and no issue is raised, recommended workaround 8 | } 9 | 10 | $ee-icons: ( 11 | 1gb : "\e06e", 12 | 3g : "\e06d", 13 | 3gb : "\e06c", 14 | 4g : "\e06b", 15 | 4gee : "\e06a", 16 | 4gee-resumptive : "\e069", 17 | 4gee-streaming : "\e068", 18 | ) 19 | -------------------------------------------------------------------------------- /its/sources/custom/S4654.css: -------------------------------------------------------------------------------- 1 | a { 2 | colr: blue; /* Noncompliant */ 3 | content-visibility: auto; /* No FP */ 4 | contain-intrinsic-size: 400px; /* No FP */ 5 | } 6 | 7 | 8 | img { 9 | -ms-interpolation-mode: bicubic; /* No FP */ 10 | } 11 | 12 | table { 13 | mso-table-lspace: 0pt; /* No FP */ 14 | mso-table-rspace: 0pt; /* No FP */ 15 | } 16 | 17 | p, a, li, td, blockquote { 18 | mso-line-height-rule: exactly; /* No FP */ 19 | } 20 | -------------------------------------------------------------------------------- /its/sources/custom/S4654.scss: -------------------------------------------------------------------------------- 1 | $light-blue-10: #c0e7f3; 2 | $light-blue-40: #4bc7e7; 3 | $teal: #23B8A7; 4 | :export { 5 | lightBlue10: $light-blue-10; /* No FP */ 6 | lightBlue40: $light-blue-40; /* No FP */ 7 | teal: $teal; /* No FP */ 8 | } 9 | 10 | my-export-class { 11 | lightBlue10: $light-blue-10; /* Noncompliant */ 12 | lightBlue40: $light-blue-40; /* Noncompliant */ 13 | teal: $teal; /* Noncompliant */ 14 | } 15 | -------------------------------------------------------------------------------- /its/sources/custom/S4660.scss: -------------------------------------------------------------------------------- 1 | & ::v-deep .q-tab__content { 2 | min-width: 0; 3 | } 4 | 5 | ion-select::part(icon) { 6 | display: none; 7 | } 8 | -------------------------------------------------------------------------------- /its/sources/custom/S4662.scss: -------------------------------------------------------------------------------- 1 | @use 'variables'; /* No FP */ 2 | 3 | @@media { 4 | display: none; 5 | } 6 | -------------------------------------------------------------------------------- /its/sources/custom/S4666.css: -------------------------------------------------------------------------------- 1 | .myclass, .myotherclass { 2 | font-size: 10px; 3 | /* < lots more styles > */ 4 | } 5 | 6 | /* particular override for myclass */ 7 | .myclass { /* No FP */ 8 | color: red; 9 | } 10 | /* particular override for myotherclass */ 11 | .myotherclass { /* No FP */ 12 | color: blue; 13 | } 14 | -------------------------------------------------------------------------------- /its/sources/custom/S4670.css: -------------------------------------------------------------------------------- 1 | unknown {} /* Noncompliant */ 2 | x-Foo {} /* Noncompliant */ 3 | x-foo {} /* No FP */ 4 | -------------------------------------------------------------------------------- /its/sources/custom/S5362.less: -------------------------------------------------------------------------------- 1 | .foo { 2 | height: calc(100% - (@a-height + @b-margin-top)); /* No FP */ 3 | } 4 | -------------------------------------------------------------------------------- /its/sources/custom/S5362.scss: -------------------------------------------------------------------------------- 1 | .foo { 2 | height: calc(100% - ($a-height + $b-margin-top)); /* No FP*/ 3 | } 4 | -------------------------------------------------------------------------------- /its/sources/custom/test.css: -------------------------------------------------------------------------------- 1 | html { 2 | line-height: 1.15; /* 1 */ 3 | -webkit-text-size-adjust: 100%; /* 2 */ 4 | } 5 | 6 | samp { 7 | font-family: monospace, monospace; /* 1 */ 8 | font-size: 1em; /* 2 */ 9 | } 10 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/bin/server: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /* 4 | * This script expects following arguments 5 | * 6 | * port - port number on which server should listen 7 | * host - host address on which server should listen 8 | */ 9 | 10 | const server = require("../lib/src/server"); 11 | 12 | const port = process.argv[2]; 13 | const host = process.argv[3]; 14 | 15 | server.start(port, host); 16 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | collectCoverageFrom: ["src/**/*.ts"], 3 | moduleFileExtensions: ["js", "ts"], 4 | testResultsProcessor: "jest-sonar-reporter", 5 | transform: { 6 | "^.+\\.ts$": "ts-jest" 7 | }, 8 | testMatch: ["/tests/**/*.test.ts"] 9 | }; 10 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "css-bundle", 3 | "version": "1.0.0", 4 | "description": "Simple node project to run stylelint", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "yarn install && yarn check-format && yarn clear && yarn compile", 8 | "prepare-package": "rm -rf node_modules && yarn install --prod", 9 | "clear": "tsc -b . --clean", 10 | "compile": "tsc -b .", 11 | "check-format": "prettier --list-different \"{src,tests}/**/*.ts\"", 12 | "format": "prettier --write \"{src,tests}/**/*.ts\"", 13 | "test": "jest" 14 | }, 15 | "author": "", 16 | "license": "LGPL-3.0", 17 | "dependencies": { 18 | "express": "4.17.1", 19 | "stylelint": "13.10.0", 20 | "body-parser": "1.19.0" 21 | }, 22 | "devDependencies": { 23 | "@types/express": "4.17.2", 24 | "@types/jest": "26.0.14", 25 | "@types/stylelint": "9.10.1", 26 | "jest": "26.4.2", 27 | "jest-sonar-reporter": "1.3.0", 28 | "prettier": "1.19.1", 29 | "ts-jest": "26.4.1", 30 | "typescript": "4.0.3" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/package/.gitignore: -------------------------------------------------------------------------------- 1 | !node_modules/ 2 | 3 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/package/node_modules/.bin/run-node: -------------------------------------------------------------------------------- 1 | ../run-node/run-node -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/package/node_modules/.yarn-integrity: -------------------------------------------------------------------------------- 1 | { 2 | "systemParams": "darwin-x64-57", 3 | "modulesFolders": [ 4 | "node_modules" 5 | ], 6 | "flags": [], 7 | "linkedModules": [], 8 | "topLevelPatterns": [ 9 | "run-node@1.0.0" 10 | ], 11 | "lockfileEntries": { 12 | "run-node@1.0.0": "https://registry.yarnpkg.com/run-node/-/run-node-1.0.0.tgz#46b50b946a2aa2d4947ae1d886e9856fd9cabe5e" 13 | }, 14 | "files": [], 15 | "artifacts": {} 16 | } -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/package/node_modules/run-node/license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Sindre Sorhus (sindresorhus.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/package/node_modules/run-node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "run-node", 3 | "version": "1.0.0", 4 | "description": "Run the Node.js binary no matter what", 5 | "license": "MIT", 6 | "repository": "sindresorhus/run-node", 7 | "author": { 8 | "name": "Sindre Sorhus", 9 | "email": "sindresorhus@gmail.com", 10 | "url": "sindresorhus.com" 11 | }, 12 | "bin": "run-node", 13 | "engines": { 14 | "node": ">=4" 15 | }, 16 | "scripts": { 17 | "test": "./run-node --version" 18 | }, 19 | "files": [ 20 | "run-node" 21 | ], 22 | "keywords": [ 23 | "run", 24 | "node", 25 | "nodejs", 26 | "node.js", 27 | "find", 28 | "binary", 29 | "bin", 30 | "execute", 31 | "which", 32 | "detect", 33 | "path", 34 | "env", 35 | "bash", 36 | "shell", 37 | "sh" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/package/node_modules/run-node/readme.md: -------------------------------------------------------------------------------- 1 | # run-node [![Build Status](https://travis-ci.org/sindresorhus/run-node.svg?branch=master)](https://travis-ci.org/sindresorhus/run-node) 2 | 3 | > Run the Node.js binary no matter what 4 | 5 | You can't always assume running `$ node file.js` will just work. The user might have the `node` binary in a non-standard location. They might be using a Node.js version manager like `nvm`, which is sourced in a subshell and not available from the outside. It also depends from where you're trying to run it. For example, GUI apps on macOS doesn't inherit the [`$PATH`](https://en.wikipedia.org/wiki/PATH_(variable)), so the `node` binary would not be found. Most projects that depend on Node.js just end up telling the user to manually set the full path to the `node` binary in some project specific settings. Now every project has to do this. [Ugh...](https://gist.github.com/cookrn/4015437) I prefer things to *just* work. With this module it will. 6 | 7 | This Bash script uses some tricks to find the Node.js binary on your system and run it. 8 | 9 | Can be used from any environment that can spawn a process (Shell, Python, Ruby, Swift, Objective-C, etc). 10 | 11 | 12 | ### npm 13 | 14 | #### Install 15 | 16 | ``` 17 | $ npm install run-node 18 | ``` 19 | 20 | #### Usage 21 | 22 | ``` 23 | $ ./node_modules/.bin/run-node file.js 24 | ``` 25 | 26 | Or in an [npm run script](https://docs.npmjs.com/cli/run-script): 27 | 28 | ```json 29 | { 30 | "start": "run-node file.js" 31 | } 32 | ``` 33 | 34 | ### Manually 35 | 36 | #### Install 37 | 38 | Download the [run-node](run-node) file: 39 | 40 | ``` 41 | $ curl -sSLO https://github.com/sindresorhus/run-node/raw/master/run-node && chmod +x run-node 42 | ``` 43 | 44 | #### Usage 45 | 46 | ``` 47 | ./run-node file.js 48 | ``` 49 | 50 | #### Customizable cache path and error message 51 | 52 | The cache path and error message are defined by the `RUN_NODE_CACHE_PATH` and `RUN_NODE_ERROR_MSG` environment variables. You could use them in a script or add them to your `~.bashrc`. 53 | 54 | Default config: 55 | 56 | ```sh 57 | export RUN_NODE_ERROR_MSG="Couldn't find the Node.js binary. Ensure you have Node.js installed. Open an issue on https://github.com/sindresorhus/run-node" 58 | export RUN_NODE_CACHE_PATH="/home/username/.node_path" 59 | ``` 60 | 61 | 62 | ## Created by 63 | 64 | - [Sindre Sorhus](https://github.com/sindresorhus) 65 | - [Mathias Fredriksson](https://github.com/mafredri) 66 | 67 | 68 | ## License 69 | 70 | MIT © [Sindre Sorhus](https://sindresorhus.com) 71 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/package/node_modules/run-node/run-node: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # MIT License © Sindre Sorhus 3 | 4 | if [[ -z $RUN_NODE_CACHE_PATH ]]; then 5 | PATH_CACHE="$HOME"/.node_path 6 | else 7 | PATH_CACHE="$RUN_NODE_CACHE_PATH" 8 | fi 9 | 10 | get_user_path() { 11 | [[ -x "/usr/libexec/path_helper" ]] && eval $(/usr/libexec/path_helper -s) 12 | echo "$($SHELL -i -l -c 'echo -e "\n"PATH=\"$PATH:\$PATH\""\n"' 2>/dev/null | grep "^PATH=")" > "$PATH_CACHE" 13 | } 14 | 15 | set_path() { 16 | if [[ -f "$PATH_CACHE" ]]; then 17 | . "$PATH_CACHE" 18 | else 19 | get_user_path 20 | . "$PATH_CACHE" 21 | fi 22 | 23 | export PATH 24 | } 25 | 26 | has_node() { 27 | command -v node >/dev/null 2>&1 28 | } 29 | 30 | # Check if we have node, otherwise inherit path from user shell 31 | if ! has_node; then 32 | set_path 33 | 34 | # Retry by deleting old path cache 35 | if ! has_node; then 36 | rm "$PATH_CACHE" 37 | set_path 38 | fi 39 | fi 40 | 41 | if has_node; then 42 | node "$@" 43 | else 44 | if [[ -z $RUN_NODE_ERROR_MSG ]]; then 45 | echo "Couldn't find the Node.js binary. Ensure you have Node.js installed. Open an issue on https://github.com/sindresorhus/run-node" 46 | else 47 | echo "$RUN_NODE_ERROR_MSG" 48 | fi 49 | fi 50 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "run-node-bundle", 3 | "version": "1.0.0", 4 | "description": "Small nested project to provide run-node", 5 | "main": "index.js", 6 | "author": "", 7 | "license": "LGPL-3.0", 8 | "dependencies": { 9 | "run-node": "1.0.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/package/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | run-node@1.0.0: 6 | version "1.0.0" 7 | resolved "https://registry.yarnpkg.com/run-node/-/run-node-1.0.0.tgz#46b50b946a2aa2d4947ae1d886e9856fd9cabe5e" 8 | integrity sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A== 9 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/src/server.ts: -------------------------------------------------------------------------------- 1 | import { Server } from "http"; 2 | import * as express from "express"; 3 | import { AddressInfo } from "net"; 4 | import * as stylelint from "stylelint"; 5 | import * as fs from "fs"; 6 | import * as bodyParser from "body-parser"; 7 | 8 | // for testing purposes 9 | let log = console.log; 10 | let logError = console.error; 11 | 12 | const MAX_REQUEST_SIZE = "50mb"; 13 | 14 | export function setLogHandlersForTests( 15 | logHandler: typeof console.log, 16 | errorHandler: typeof console.error 17 | ) { 18 | log = logHandler; 19 | logError = errorHandler; 20 | } 21 | 22 | export function start(port = 0, host = "127.0.0.1"): Promise { 23 | return new Promise(resolve => { 24 | log("DEBUG starting stylelint-bridge server at port", port); 25 | const app = express(); 26 | app.use(bodyParser.json({ limit: MAX_REQUEST_SIZE })); 27 | app.post("/analyze", analyzeWithStylelint); 28 | app.get("/status", (_: express.Request, resp: express.Response) => 29 | resp.send("OK!") 30 | ); 31 | 32 | app.post("/close", (_req: express.Request, resp: express.Response) => { 33 | console.log("DEBUG stylelint-bridge server will shutdown"); 34 | resp.end(() => { 35 | server.close(); 36 | }); 37 | }); 38 | 39 | // every time something is wrong we log error and send empty response (with 0 issues) 40 | // it's important to keep this call last in configuring "app" 41 | app.use( 42 | ( 43 | error: any, 44 | _req: express.Request, 45 | response: express.Response, 46 | _next: any 47 | ) => processError(error, response) 48 | ); 49 | 50 | const server = app.listen(port, host, () => { 51 | log( 52 | "DEBUG stylelint-bridge server is running at port", 53 | (server.address() as AddressInfo).port 54 | ); 55 | resolve(server); 56 | }); 57 | }); 58 | } 59 | 60 | function analyzeWithStylelint( 61 | request: express.Request, 62 | response: express.Response 63 | ) { 64 | const parsedRequest = request.body as AnalysisInput; 65 | const { filePath, fileContent, configFile } = parsedRequest; 66 | const code = 67 | typeof fileContent == "string" ? fileContent : getFileContent(filePath); 68 | const options = { 69 | code, 70 | codeFilename: filePath, 71 | configFile 72 | }; 73 | 74 | stylelint 75 | .lint(options) 76 | .then(result => response.json(toIssues(result.results, filePath))) 77 | .catch(error => processError(error, response)); 78 | } 79 | 80 | function processError(error: any, response: express.Response) { 81 | logError(error); 82 | response.json([]); 83 | } 84 | 85 | function toIssues(results: stylelint.LintResult[], filePath: string): Issue[] { 86 | const analysisResponse: Issue[] = []; 87 | // we should have only one element in 'results' as we are analyzing only 1 file 88 | results.forEach(result => { 89 | // to avoid reporting on "fake" source like 90 | if (result.source !== filePath) { 91 | log( 92 | `DEBUG For file [${filePath}] received issues with [${result.source}] as a source. They will not be reported.` 93 | ); 94 | return; 95 | } 96 | result.warnings.forEach(warning => 97 | analysisResponse.push({ 98 | line: warning.line, 99 | text: warning.text, 100 | rule: warning.rule 101 | }) 102 | ); 103 | }); 104 | return analysisResponse; 105 | } 106 | 107 | function getFileContent(filePath: string) { 108 | const fileContent = fs.readFileSync(filePath, { encoding: "utf8" }); 109 | // strip BOM 110 | if (fileContent.charCodeAt(0) === 0xfeff) { 111 | return fileContent.slice(1); 112 | } 113 | return fileContent; 114 | } 115 | 116 | export interface AnalysisInput { 117 | filePath: string; 118 | fileContent: string | undefined; 119 | configFile: string; 120 | } 121 | 122 | export interface Issue { 123 | line: number; 124 | rule: string; 125 | text: string; 126 | } 127 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/tests/fixtures/file-bom.css: -------------------------------------------------------------------------------- 1 | p { 2 | } 3 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/tests/fixtures/file.css: -------------------------------------------------------------------------------- 1 | p { } 2 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/tests/fixtures/file.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Page Title 5 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/tests/fixtures/file.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Index 5 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/tests/fixtures/stylelintconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "block-no-empty": true 4 | } 5 | } -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/tests/server-mock-stylelint.test.ts: -------------------------------------------------------------------------------- 1 | import { start, setLogHandlersForTests } from "../src/server"; 2 | import { Server } from "http"; 3 | import * as path from "path"; 4 | import { promisify } from "util"; 5 | import * as stylelint from "stylelint"; 6 | import { postToServer } from "./utils"; 7 | 8 | const filePath = path.join(__dirname, "fixtures", "file.css"); 9 | 10 | const request = JSON.stringify({ 11 | filePath, 12 | configFile: path.join(__dirname, "fixtures", "stylelintconfig.json") 13 | }); 14 | 15 | jest.mock("stylelint"); 16 | 17 | describe("server", () => { 18 | let server: Server; 19 | let close: () => Promise; 20 | const logSpy = jest.fn(); 21 | const errorSpy = jest.fn(); 22 | 23 | beforeAll(async () => { 24 | setLogHandlersForTests(logSpy, errorSpy); 25 | server = await start(); 26 | close = promisify(server.close.bind(server)); 27 | }); 28 | 29 | afterAll(async () => { 30 | jest.restoreAllMocks(); 31 | await close(); 32 | }); 33 | 34 | it("should not return issues for not original file", async () => { 35 | (stylelint.lint as any).mockResolvedValue({ 36 | results: [{ source: "foo.bar" }] 37 | }); 38 | const response = await postToServer(request, "/analyze", server); 39 | expect(JSON.parse(response)).toEqual([]); 40 | expect(logSpy).toHaveBeenCalledWith( 41 | `DEBUG For file [${filePath}] received issues with [foo.bar] as a source. They will not be reported.` 42 | ); 43 | }); 44 | 45 | it("should not return issues when failed promise returned", async () => { 46 | (stylelint.lint as any).mockRejectedValue("some reason"); 47 | const response = await postToServer(request, "/analyze", server); 48 | expect(JSON.parse(response)).toEqual([]); 49 | expect(errorSpy).toHaveBeenCalledWith("some reason"); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/tests/utils.ts: -------------------------------------------------------------------------------- 1 | import * as http from "http"; 2 | import { Server } from "http"; 3 | import { AddressInfo } from "net"; 4 | 5 | export function postToServer( 6 | data: string, 7 | endpoint: string, 8 | server: Server 9 | ): Promise { 10 | const options = { 11 | host: "localhost", 12 | port: (server.address()).port, 13 | path: endpoint, 14 | method: "POST", 15 | headers: { 16 | "Content-Type": "application/json" 17 | } 18 | }; 19 | 20 | return new Promise((resolve, reject) => { 21 | let response = ""; 22 | 23 | const req = http.request(options, res => { 24 | res.on("data", chunk => { 25 | response += chunk; 26 | }); 27 | 28 | res.on("end", () => resolve(response)); 29 | }); 30 | 31 | req.on("error", reject); 32 | 33 | req.write(data); 34 | req.end(); 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /sonar-css-plugin/css-bundle/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "lib": ["dom", "es2017"], 6 | "declaration": true, 7 | "outDir": "./lib", 8 | "strict": true, 9 | "sourceMap": true, 10 | "noUnusedLocals": true, 11 | "noUnusedParameters": true, 12 | "allowSyntheticDefaultImports": true, 13 | "composite": true, 14 | "typeRoots": ["./node_modules/@types"], 15 | "skipLibCheck": true 16 | }, 17 | "include": ["src/**/*"] 18 | } 19 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssLanguage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin; 21 | 22 | import org.sonar.api.config.Configuration; 23 | import org.sonar.api.resources.AbstractLanguage; 24 | 25 | public class CssLanguage extends AbstractLanguage { 26 | 27 | public static final String KEY = "css"; 28 | 29 | private Configuration configuration; 30 | 31 | public CssLanguage(Configuration configuration) { 32 | super(KEY, "CSS"); 33 | this.configuration = configuration; 34 | } 35 | 36 | @Override 37 | public String[] getFileSuffixes() { 38 | return configuration.getStringArray(CssPlugin.FILE_SUFFIXES_KEY); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssPlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin; 21 | 22 | import org.sonar.api.Plugin; 23 | import org.sonar.api.config.PropertyDefinition; 24 | import org.sonar.api.resources.Qualifiers; 25 | import org.sonar.css.plugin.server.NodeDeprecationWarning; 26 | import org.sonar.css.plugin.server.bundle.CssAnalyzerBundle; 27 | import org.sonar.css.plugin.metrics.MetricSensor; 28 | import org.sonar.css.plugin.server.CssAnalyzerBridgeServer; 29 | 30 | public class CssPlugin implements Plugin { 31 | 32 | static final String FILE_SUFFIXES_KEY = "sonar.css.file.suffixes"; 33 | public static final String FILE_SUFFIXES_DEFVALUE = ".css,.less,.scss"; 34 | 35 | public static final String STYLELINT_REPORT_PATHS = "sonar.css.stylelint.reportPaths"; 36 | public static final String STYLELINT_REPORT_PATHS_DEFAULT_VALUE = ""; 37 | 38 | public static final String FORMER_NODE_EXECUTABLE = "sonar.css.node"; 39 | 40 | private static final String CSS_CATEGORY = "CSS"; 41 | private static final String LINTER_SUBCATEGORY = "Popular Rule Engines"; 42 | private static final String GENERAL_SUBCATEGORY = "General"; 43 | 44 | @Override 45 | public void define(Context context) { 46 | context.addExtensions( 47 | MetricSensor.class, 48 | CssLanguage.class, 49 | SonarWayProfile.class, 50 | CssRulesDefinition.class, 51 | CssAnalyzerBundle.class, 52 | CssAnalyzerBridgeServer.class, 53 | CssRuleSensor.class, 54 | StylelintReportSensor.class, 55 | MinifiedFilesFilter.class, 56 | NodeDeprecationWarning.class, 57 | 58 | PropertyDefinition.builder(FILE_SUFFIXES_KEY) 59 | .defaultValue(FILE_SUFFIXES_DEFVALUE) 60 | .name("File Suffixes") 61 | .description("List of suffixes for files to analyze.") 62 | .subCategory(GENERAL_SUBCATEGORY) 63 | .category(CSS_CATEGORY) 64 | .onQualifiers(Qualifiers.PROJECT) 65 | .multiValues(true) 66 | .build() 67 | ); 68 | 69 | context.addExtension( 70 | PropertyDefinition.builder(STYLELINT_REPORT_PATHS) 71 | .defaultValue(STYLELINT_REPORT_PATHS_DEFAULT_VALUE) 72 | .name("Stylelint Report Files") 73 | .description("Paths (absolute or relative) to the JSON files with stylelint issues.") 74 | .onQualifiers(Qualifiers.PROJECT) 75 | .subCategory(LINTER_SUBCATEGORY) 76 | .category(CSS_CATEGORY) 77 | .multiValues(true) 78 | .build()); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssRulesDefinition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin; 21 | 22 | import org.sonar.api.server.rule.RulesDefinition; 23 | import org.sonarsource.analyzer.commons.RuleMetadataLoader; 24 | 25 | import static org.sonar.css.plugin.SonarWayProfile.PROFILE_PATH; 26 | 27 | public class CssRulesDefinition implements RulesDefinition { 28 | 29 | public static final String REPOSITORY_KEY = "css"; 30 | public static final String RULE_REPOSITORY_NAME = "SonarAnalyzer"; 31 | 32 | public static final String RESOURCE_FOLDER = "org/sonar/l10n/css/rules/"; 33 | 34 | @Override 35 | public void define(Context context) { 36 | NewRepository repository = context 37 | .createRepository(REPOSITORY_KEY, CssLanguage.KEY) 38 | .setName(RULE_REPOSITORY_NAME); 39 | 40 | RuleMetadataLoader ruleMetadataLoader = new RuleMetadataLoader(RESOURCE_FOLDER + REPOSITORY_KEY, PROFILE_PATH); 41 | ruleMetadataLoader.addRulesByAnnotatedClass(repository, CssRules.getRuleClasses()); 42 | repository.done(); 43 | 44 | StylelintReportSensor.getStylelintRuleLoader().createExternalRuleRepository(context); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/MinifiedFilesFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin; 21 | 22 | import java.io.IOException; 23 | import org.sonar.api.batch.fs.InputFile; 24 | import org.sonar.api.batch.fs.InputFileFilter; 25 | import org.sonar.api.utils.log.Logger; 26 | import org.sonar.api.utils.log.Loggers; 27 | 28 | public class MinifiedFilesFilter implements InputFileFilter { 29 | 30 | private static final int AVERAGE_LINE_LENGTH_THRESHOLD = 200; 31 | 32 | private static final Logger LOG = Loggers.get(MinifiedFilesFilter.class); 33 | 34 | @Override 35 | public boolean accept(InputFile file) { 36 | if (!CssLanguage.KEY.equals(file.language())) { 37 | return true; 38 | } 39 | 40 | try { 41 | boolean isMinified = hasMinifiedFileName(file) || hasExcessiveAverageLineLength(file); 42 | if (isMinified) { 43 | LOG.debug("File [" + file.uri() + "] looks like a minified file and will not be analyzed"); 44 | } 45 | return !isMinified; 46 | 47 | } catch (IOException e) { 48 | throw new IllegalStateException("Failed to read input file", e); 49 | } 50 | } 51 | 52 | private static boolean hasMinifiedFileName(InputFile file) { 53 | String fileName = file.filename(); 54 | return fileName.endsWith("-min.css") || fileName.endsWith(".min.css"); 55 | } 56 | 57 | private static boolean hasExcessiveAverageLineLength(InputFile file) throws IOException { 58 | int averageLineLength = file.contents().length() / file.lines(); 59 | return averageLineLength > AVERAGE_LINE_LENGTH_THRESHOLD; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/SonarWayProfile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin; 21 | 22 | import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; 23 | import org.sonarsource.analyzer.commons.BuiltInQualityProfileJsonLoader; 24 | 25 | import static org.sonar.css.plugin.CssRulesDefinition.REPOSITORY_KEY; 26 | import static org.sonar.css.plugin.CssRulesDefinition.RESOURCE_FOLDER; 27 | 28 | public class SonarWayProfile implements BuiltInQualityProfilesDefinition { 29 | 30 | public static final String PROFILE_NAME = "Sonar way"; 31 | public static final String PROFILE_PATH = RESOURCE_FOLDER + CssRulesDefinition.REPOSITORY_KEY + "/Sonar_way_profile.json"; 32 | 33 | @Override 34 | public void define(Context context) { 35 | NewBuiltInQualityProfile profile = context.createBuiltInQualityProfile(PROFILE_NAME, CssLanguage.KEY); 36 | BuiltInQualityProfileJsonLoader.load(profile, REPOSITORY_KEY, PROFILE_PATH); 37 | profile.done(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/StylelintReport.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin; 21 | 22 | public class StylelintReport { 23 | 24 | private StylelintReport(){ 25 | } 26 | 27 | static class IssuesPerFile { 28 | String source; 29 | Issue[] warnings; 30 | } 31 | 32 | static class Issue { 33 | int line; 34 | String rule; 35 | String text; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/metrics/CssToken.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.metrics; 21 | 22 | import com.sonar.sslr.api.Token; 23 | import com.sonar.sslr.api.TokenType; 24 | import org.sonarsource.analyzer.commons.TokenLocation; 25 | 26 | public class CssToken { 27 | CssTokenType type; 28 | String text; 29 | Integer startLine; 30 | Integer startColumn; 31 | Integer endLine; 32 | Integer endColumn; 33 | 34 | public CssToken(Token token) { 35 | TokenType tokenType = token.getType(); 36 | this.type = (CssTokenType)tokenType; 37 | this.text = token.getValue(); 38 | 39 | TokenLocation tokenLocation = new TokenLocation(token.getLine(), token.getColumn(), token.getValue()); 40 | this.startLine = tokenLocation.startLine(); 41 | this.startColumn = tokenLocation.startLineOffset(); 42 | this.endLine = tokenLocation.endLine(); 43 | this.endColumn = tokenLocation.endLineOffset(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/metrics/CssTokenType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.metrics; 21 | 22 | import com.sonar.sslr.api.AstNode; 23 | import com.sonar.sslr.api.TokenType; 24 | 25 | public enum CssTokenType implements TokenType { 26 | COMMENT, 27 | PUNCTUATOR, 28 | NUMBER, 29 | STRING, 30 | AT_IDENTIFIER, 31 | HASH_IDENTIFIER, 32 | DOLLAR_IDENTIFIER, 33 | IDENTIFIER; 34 | 35 | @Override 36 | public String getName() { 37 | return name(); 38 | } 39 | 40 | @Override 41 | public String getValue() { 42 | return name(); 43 | } 44 | 45 | @Override 46 | public boolean hasToBeSkippedFromAst(AstNode node) { 47 | return false; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/metrics/Tokenizer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.metrics; 21 | 22 | import com.sonar.sslr.api.Token; 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | import java.util.stream.Collectors; 26 | 27 | public class Tokenizer { 28 | 29 | public List tokenize(String css) { 30 | List tokenList = CssLexer.create().lex(css); 31 | 32 | // remove last token (EOF token) 33 | List cloneTokenList = new ArrayList<>(tokenList); 34 | cloneTokenList.remove(cloneTokenList.size() - 1); 35 | 36 | return cloneTokenList.stream().map(CssToken::new).collect(Collectors.toList()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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 | @javax.annotation.ParametersAreNonnullByDefault 21 | package org.sonar.css.plugin; 22 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/AtRuleNoUnknown.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import java.util.Arrays; 23 | import java.util.List; 24 | import org.sonar.check.Rule; 25 | import org.sonar.check.RuleProperty; 26 | 27 | import static org.sonar.css.plugin.rules.RuleUtils.splitAndTrim; 28 | 29 | @Rule(key = "S4662") 30 | public class AtRuleNoUnknown implements CssRule { 31 | 32 | private static final String DEFAULT_IGNORED_AT_RULES = "value,at-root,content,debug,each,else,error,for,function,if,include,mixin,return,warn,while,extend,use,/^@.*/"; 33 | 34 | @RuleProperty( 35 | key = "ignoreAtRules", 36 | description = "Comma-separated list of \"at-rules\" to consider as valid.", 37 | defaultValue = "" + DEFAULT_IGNORED_AT_RULES) 38 | String ignoredAtRules = DEFAULT_IGNORED_AT_RULES; 39 | 40 | @Override 41 | public String stylelintKey() { 42 | return "at-rule-no-unknown"; 43 | } 44 | 45 | @Override 46 | public List stylelintOptions() { 47 | return Arrays.asList(true, new StylelintIgnoreOption(splitAndTrim(ignoredAtRules))); 48 | } 49 | 50 | private static class StylelintIgnoreOption { 51 | // Used by GSON serialization 52 | private final List ignoreAtRules; 53 | 54 | StylelintIgnoreOption(List ignoreAtRules) { 55 | this.ignoreAtRules = ignoreAtRules; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/BlockNoEmpty.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S4658") 25 | public class BlockNoEmpty implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "block-no-empty"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/ColorNoInvalidHex.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S4647") 25 | public class ColorNoInvalidHex implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "color-no-invalid-hex"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/CommentNoEmpty.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S4663") 25 | public class CommentNoEmpty implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "comment-no-empty"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/CssRule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import java.util.Collections; 23 | import java.util.List; 24 | 25 | public interface CssRule { 26 | 27 | String stylelintKey(); 28 | 29 | default List stylelintOptions() { 30 | return Collections.emptyList(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/DeclarationBlockNoDuplicateProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import java.util.Arrays; 23 | import java.util.Collections; 24 | import java.util.List; 25 | import org.sonar.check.Rule; 26 | import org.sonar.check.RuleProperty; 27 | 28 | @Rule(key = "S4656") 29 | public class DeclarationBlockNoDuplicateProperties implements CssRule { 30 | 31 | private static final boolean DEFAULT_IGNORE_FALLBACKS = true; 32 | 33 | @RuleProperty( 34 | key = "ignoreFallbacks", 35 | description = "Ignore consecutive duplicated properties with different values.", 36 | defaultValue = "" + DEFAULT_IGNORE_FALLBACKS) 37 | boolean ignoreFallbacks = DEFAULT_IGNORE_FALLBACKS; 38 | 39 | @Override 40 | public String stylelintKey() { 41 | return "declaration-block-no-duplicate-properties"; 42 | } 43 | 44 | @Override 45 | public List stylelintOptions() { 46 | return ignoreFallbacks ? Arrays.asList(true, new StylelintIgnoreOption()) : Collections.emptyList(); 47 | } 48 | 49 | private static class StylelintIgnoreOption { 50 | private final List ignore = Collections.singletonList("consecutive-duplicates-with-different-values"); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/DeclarationBlockNoShorthandPropertyOverrides.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S4657") 25 | public class DeclarationBlockNoShorthandPropertyOverrides implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "declaration-block-no-shorthand-property-overrides"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/FontFamilyNoDuplicateNames.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S4648") 25 | public class FontFamilyNoDuplicateNames implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "font-family-no-duplicate-names"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/FontFamilyNoMissingGenericFamilyKeyword.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S4649") 25 | public class FontFamilyNoMissingGenericFamilyKeyword implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "font-family-no-missing-generic-family-keyword"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/FunctionCalcNoInvalid.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S5362") 25 | public class FunctionCalcNoInvalid implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "function-calc-no-invalid"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/FunctionCalcNoUnspacedOperator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S4650") 25 | public class FunctionCalcNoUnspacedOperator implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "function-calc-no-unspaced-operator"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/FunctionLinearGradientNoNonstandardDirection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S4651") 25 | public class FunctionLinearGradientNoNonstandardDirection implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "function-linear-gradient-no-nonstandard-direction"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/KeyframeDeclarationNoImportant.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S4655") 25 | public class KeyframeDeclarationNoImportant implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "keyframe-declaration-no-important"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/MediaFeatureNameNoUnknown.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S4661") 25 | public class MediaFeatureNameNoUnknown implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "media-feature-name-no-unknown"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/NoDescendingSpecificity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S4664") 25 | public class NoDescendingSpecificity implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "no-descending-specificity"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/NoDuplicateAtImportRules.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S1128") 25 | public class NoDuplicateAtImportRules implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "no-duplicate-at-import-rules"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/NoDuplicateSelectors.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S4666") 25 | public class NoDuplicateSelectors implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "no-duplicate-selectors"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/NoEmptySource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S4667") 25 | public class NoEmptySource implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "no-empty-source"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/NoExtraSemicolons.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S1116") 25 | public class NoExtraSemicolons implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "no-extra-semicolons"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/NoInvalidDoubleSlashComments.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S4668") 25 | public class NoInvalidDoubleSlashComments implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "no-invalid-double-slash-comments"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/PropertyNoUnknown.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | import java.util.Arrays; 25 | import java.util.List; 26 | import org.sonar.check.RuleProperty; 27 | 28 | import static org.sonar.css.plugin.rules.RuleUtils.splitAndTrim; 29 | 30 | 31 | @Rule(key = "S4654") 32 | public class PropertyNoUnknown implements CssRule { 33 | 34 | private static final String DEFAULT_IGNORED_PROPERTIES = "composes, /^mso-/"; 35 | private static final String DEFAULT_IGNORED_SELECTORS = "/^:export.*/, /^:import.*/"; 36 | 37 | @RuleProperty( 38 | key = "ignoreTypes", 39 | description = "Comma-separated list of strings and/or regular expressions for properties to consider as valid.", 40 | defaultValue = "" + DEFAULT_IGNORED_PROPERTIES) 41 | String ignoreProperties = DEFAULT_IGNORED_PROPERTIES; 42 | 43 | @RuleProperty( 44 | key = "ignoreSelectors", 45 | description = "Comma-separated list of strings and/or regular expressions for selectors to consider as valid.", 46 | defaultValue = "" + DEFAULT_IGNORED_SELECTORS) 47 | String ignoreSelectors = DEFAULT_IGNORED_SELECTORS; 48 | 49 | @Override 50 | public String stylelintKey() { 51 | return "property-no-unknown"; 52 | } 53 | 54 | @Override 55 | public List stylelintOptions() { 56 | return Arrays.asList(true, new StylelintIgnoreOption(splitAndTrim(ignoreProperties), splitAndTrim(ignoreSelectors))); 57 | } 58 | 59 | private static class StylelintIgnoreOption { 60 | // Used by GSON serialization 61 | private final List ignoreProperties; 62 | private final List ignoreSelectors; 63 | 64 | private StylelintIgnoreOption(List ignoreProperties, List ignoreSelectors) { 65 | this.ignoreProperties = ignoreProperties; 66 | this.ignoreSelectors = ignoreSelectors; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/RuleUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import java.util.Arrays; 23 | import java.util.List; 24 | import java.util.stream.Collectors; 25 | 26 | public class RuleUtils { 27 | 28 | private RuleUtils(){ 29 | } 30 | 31 | public static List splitAndTrim(String parameterValue) { 32 | String[] split = parameterValue.split(","); 33 | return Arrays.stream(split).map(String::trim).collect(Collectors.toList()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/SelectorPseudoClassNoUnknown.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import java.util.Arrays; 23 | import java.util.List; 24 | import org.sonar.check.Rule; 25 | import org.sonar.check.RuleProperty; 26 | 27 | import static org.sonar.css.plugin.rules.RuleUtils.splitAndTrim; 28 | 29 | @Rule(key = "S4659") 30 | public class SelectorPseudoClassNoUnknown implements CssRule { 31 | 32 | private static final String DEFAULT_IGNORED_PSEUDO_CLASSES = "local,global,export,import"; 33 | 34 | @RuleProperty( 35 | key = "ignorePseudoClasses", 36 | description = "Comma-separated list of strings and/or regular expressions for pseudo classes to consider as valid.", 37 | defaultValue = "" + DEFAULT_IGNORED_PSEUDO_CLASSES) 38 | String ignoredPseudoClasses = DEFAULT_IGNORED_PSEUDO_CLASSES; 39 | 40 | @Override 41 | public String stylelintKey() { 42 | return "selector-pseudo-class-no-unknown"; 43 | } 44 | 45 | @Override 46 | public List stylelintOptions() { 47 | return Arrays.asList(true, new StylelintIgnoreOption(splitAndTrim(ignoredPseudoClasses))); 48 | } 49 | 50 | 51 | private static class StylelintIgnoreOption { 52 | // Used by GSON serialization 53 | private final List ignorePseudoClasses; 54 | 55 | StylelintIgnoreOption(List ignorePseudoClasses) { 56 | this.ignorePseudoClasses = ignorePseudoClasses; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/SelectorPseudoElementNoUnknown.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import java.util.Arrays; 23 | import java.util.List; 24 | import org.sonar.check.Rule; 25 | import org.sonar.check.RuleProperty; 26 | 27 | import static org.sonar.css.plugin.rules.RuleUtils.splitAndTrim; 28 | 29 | @Rule(key = "S4660") 30 | public class SelectorPseudoElementNoUnknown implements CssRule { 31 | 32 | private static final String DEFAULT_IGNORE_PSEUDO_ELEMENTS = "ng-deep,v-deep"; 33 | 34 | @Override 35 | public String stylelintKey() { 36 | return "selector-pseudo-element-no-unknown"; 37 | } 38 | 39 | @RuleProperty( 40 | key = "ignorePseudoElements", 41 | description = "Comma-separated list of regular expressions or strings to ignore (e.g. /^custom-/).", 42 | defaultValue = "" + DEFAULT_IGNORE_PSEUDO_ELEMENTS) 43 | String ignorePseudoElements = DEFAULT_IGNORE_PSEUDO_ELEMENTS; 44 | 45 | @Override 46 | public List stylelintOptions() { 47 | return Arrays.asList(true, new StylelintIgnorePseudoElementsOption(splitAndTrim(ignorePseudoElements))); 48 | } 49 | 50 | private static class StylelintIgnorePseudoElementsOption { 51 | // Used by GSON serialization 52 | private final List ignorePseudoElements; 53 | 54 | StylelintIgnorePseudoElementsOption(List ignorePseudoElements) { 55 | this.ignorePseudoElements = ignorePseudoElements; 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/SelectorTypeNoUnknown.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import java.util.Arrays; 23 | import java.util.List; 24 | import org.sonar.check.Rule; 25 | import org.sonar.check.RuleProperty; 26 | 27 | import static org.sonar.css.plugin.rules.RuleUtils.splitAndTrim; 28 | 29 | @Rule(key = "S4670") 30 | public class SelectorTypeNoUnknown implements CssRule { 31 | 32 | // prefixes for Angular Material (mat, md), Font Awesome (fa) 33 | private static final String DEFAULT_IGNORED_TYPES = "/^(mat|md|fa)-/"; 34 | 35 | private static final String DEFAULT_IGNORE = "custom-elements"; 36 | 37 | @RuleProperty( 38 | key = "ignoreTypes", 39 | description = "Comma-separated list of regular expressions for selector types to consider as valid.", 40 | defaultValue = "" + DEFAULT_IGNORED_TYPES) 41 | String ignoreTypes = DEFAULT_IGNORED_TYPES; 42 | 43 | @RuleProperty( 44 | key = "ignore", 45 | description = "Comma-separated list of ignored elements. The possible values are:\n" + 46 | "\"custom-elements\": Allow custom elements (e.g \"x-foo\").\n" + 47 | "\"default-namespace\": Allow unknown type selectors if they belong to the default namespace.", 48 | defaultValue = "" + DEFAULT_IGNORE) 49 | String ignore = DEFAULT_IGNORE; 50 | 51 | @Override 52 | public String stylelintKey() { 53 | return "selector-type-no-unknown"; 54 | } 55 | 56 | @Override 57 | public List stylelintOptions() { 58 | return Arrays.asList(true, new StylelintIgnoreOption(splitAndTrim(ignoreTypes), splitAndTrim(ignore))); 59 | } 60 | 61 | private static class StylelintIgnoreOption { 62 | // Used by GSON serialization 63 | private final List ignoreTypes; 64 | private final List ignore; 65 | 66 | StylelintIgnoreOption(List ignoreTypes, List ignore) { 67 | this.ignoreTypes = ignoreTypes; 68 | this.ignore = ignore; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/StringNoNewline.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import org.sonar.check.Rule; 23 | 24 | @Rule(key = "S4652") 25 | public class StringNoNewline implements CssRule { 26 | 27 | @Override 28 | public String stylelintKey() { 29 | return "string-no-newline"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/UnitNoUnknown.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.rules; 21 | 22 | import java.util.Arrays; 23 | import java.util.List; 24 | import org.sonar.check.Rule; 25 | 26 | @Rule(key = "S4653") 27 | public class UnitNoUnknown implements CssRule { 28 | 29 | @Override 30 | public String stylelintKey() { 31 | return "unit-no-unknown"; 32 | } 33 | 34 | @Override 35 | public List stylelintOptions() { 36 | return Arrays.asList(true, new StylelintIgnoreOption()); 37 | } 38 | 39 | private static class StylelintIgnoreOption { 40 | // Used by GSON serialization 41 | private final String[] ignoreUnits = {"x"}; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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 | @javax.annotation.ParametersAreNonnullByDefault 21 | package org.sonar.css.plugin.rules; 22 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/server/NetUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.server; 21 | 22 | import java.io.IOException; 23 | import java.net.ServerSocket; 24 | 25 | public class NetUtils { 26 | 27 | private NetUtils() { 28 | } 29 | 30 | public static int findOpenPort() throws IOException { 31 | try (ServerSocket socket = new ServerSocket(0)) { 32 | return socket.getLocalPort(); 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/server/NodeDeprecationWarning.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.server; 21 | 22 | import javax.annotation.Nullable; 23 | import org.sonar.api.SonarEdition; 24 | import org.sonar.api.SonarProduct; 25 | import org.sonar.api.SonarRuntime; 26 | import org.sonar.api.notifications.AnalysisWarnings; 27 | import org.sonar.api.scanner.ScannerSide; 28 | import org.sonar.api.utils.log.Logger; 29 | import org.sonar.api.utils.log.Loggers; 30 | import org.sonarsource.api.sonarlint.SonarLintSide; 31 | 32 | @ScannerSide 33 | @SonarLintSide(lifespan = SonarLintSide.MULTIPLE_ANALYSES) 34 | public class NodeDeprecationWarning { 35 | 36 | private static final Logger LOG = Loggers.get(NodeDeprecationWarning.class); 37 | private static final int MIN_RECOMMENDED_NODE_VERSION = 12; 38 | private final SonarRuntime sonarRuntime; 39 | private final AnalysisWarnings analysisWarnings; 40 | 41 | public NodeDeprecationWarning(SonarRuntime sonarRuntime) { 42 | this(sonarRuntime, null); 43 | } 44 | 45 | public NodeDeprecationWarning(SonarRuntime sonarRuntime, @Nullable AnalysisWarnings analysisWarnings) { 46 | this.sonarRuntime = sonarRuntime; 47 | this.analysisWarnings = analysisWarnings; 48 | } 49 | 50 | void logNodeDeprecation(int actualNodeVersion) { 51 | if (actualNodeVersion < MIN_RECOMMENDED_NODE_VERSION) { 52 | String msg = String.format("You are using Node.js version %d, which reached end-of-life. " + 53 | "Support for this version will be dropped in future release, please upgrade Node.js to more recent version.", 54 | actualNodeVersion); 55 | LOG.warn(msg); 56 | if (isSonarQube() && analysisWarnings != null) { 57 | analysisWarnings.addUnique(msg); 58 | } 59 | } 60 | } 61 | 62 | private boolean isSonarQube() { 63 | return sonarRuntime.getProduct() == SonarProduct.SONARQUBE && sonarRuntime.getEdition() != SonarEdition.SONARCLOUD; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/server/bundle/Bundle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.server.bundle; 21 | 22 | import java.nio.file.Path; 23 | import org.sonarsource.nodejs.BundlePathResolver; 24 | 25 | public interface Bundle extends BundlePathResolver { 26 | 27 | void deploy(Path deployLocation); 28 | 29 | /** 30 | * should be called after deploy(Path deployLocation) 31 | */ 32 | String startServerScript(); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/server/bundle/CssAnalyzerBundle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.server.bundle; 21 | 22 | import java.io.InputStream; 23 | import java.nio.file.Path; 24 | import java.nio.file.Paths; 25 | import org.sonar.api.internal.google.common.annotations.VisibleForTesting; 26 | import org.sonar.api.scanner.ScannerSide; 27 | import org.sonar.api.utils.log.Logger; 28 | import org.sonar.api.utils.log.Loggers; 29 | import org.sonar.api.utils.log.Profiler; 30 | import org.sonarsource.api.sonarlint.SonarLintSide; 31 | 32 | import static org.sonarsource.api.sonarlint.SonarLintSide.MULTIPLE_ANALYSES; 33 | 34 | @ScannerSide 35 | @SonarLintSide(lifespan = MULTIPLE_ANALYSES) 36 | public class CssAnalyzerBundle implements Bundle { 37 | 38 | private static final Logger LOG = Loggers.get(CssAnalyzerBundle.class); 39 | private static final Profiler PROFILER = Profiler.createIfDebug(LOG); 40 | 41 | // this archive is created in css-bundle module 42 | private static final String DEFAULT_BUNDLE_LOCATION = "/css-bundle.zip"; 43 | private static final Path DEFAULT_STARTUP_SCRIPT = Paths.get("css-bundle", "bin", "server"); 44 | 45 | final String bundleLocation; 46 | 47 | private String startServerScript = DEFAULT_STARTUP_SCRIPT.toString(); 48 | private Path deployLocation; 49 | 50 | public CssAnalyzerBundle() { 51 | this(DEFAULT_BUNDLE_LOCATION); 52 | } 53 | 54 | @VisibleForTesting 55 | CssAnalyzerBundle(String bundleLocation) { 56 | this.bundleLocation = bundleLocation; 57 | } 58 | 59 | @Override 60 | public void deploy(Path deployLocation) { 61 | this.deployLocation = deployLocation; 62 | PROFILER.startDebug("Deploying bundle"); 63 | LOG.debug("Deploying css-bundle into {}", deployLocation); 64 | InputStream bundle = getClass().getResourceAsStream(bundleLocation); 65 | if (bundle == null) { 66 | throw new IllegalStateException("css-bundle not found in " + bundleLocation); 67 | } 68 | try { 69 | LOG.debug("Deploying css-bundle to {}", deployLocation.toAbsolutePath()); 70 | Zip.extract(bundle, deployLocation); 71 | startServerScript = deployLocation.resolve(DEFAULT_STARTUP_SCRIPT).toAbsolutePath().toString(); 72 | } catch (Exception e) { 73 | throw new IllegalStateException("Failed to deploy css-bundle (with classpath '" + bundleLocation + "')", e); 74 | } 75 | PROFILER.stopDebug(); 76 | } 77 | 78 | @Override 79 | public String startServerScript() { 80 | return startServerScript; 81 | } 82 | 83 | @Override 84 | public String resolve(String relativePath) { 85 | return deployLocation.resolve("css-bundle").resolve(relativePath).toString(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/server/bundle/Zip.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.server.bundle; 21 | 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.nio.file.Files; 25 | import java.nio.file.Path; 26 | import java.nio.file.StandardCopyOption; 27 | import java.util.zip.ZipEntry; 28 | import java.util.zip.ZipInputStream; 29 | 30 | public class Zip { 31 | 32 | private Zip() { 33 | // utility class 34 | } 35 | 36 | public static void extract(InputStream bundle, Path destination) throws IOException { 37 | try (ZipInputStream zip = new ZipInputStream(bundle)) { 38 | ZipEntry entry = zip.getNextEntry(); 39 | if (entry == null) { 40 | throw new IllegalStateException("At least one entry expected."); 41 | } 42 | while (entry != null) { 43 | Path entryDestination = entryPath(destination, entry); 44 | if (entry.isDirectory()) { 45 | Files.createDirectories(entryDestination); 46 | } else { 47 | Files.copy(zip, entryDestination, StandardCopyOption.REPLACE_EXISTING); 48 | } 49 | zip.closeEntry(); 50 | entry = zip.getNextEntry(); 51 | } 52 | } 53 | } 54 | 55 | private static Path entryPath(Path targetPath, ZipEntry entry) { 56 | Path entryPath = targetPath.resolve(entry.getName()).normalize(); 57 | if (!entryPath.startsWith(targetPath)) { 58 | throw new IllegalStateException("Archive entry " + entry.getName() + " is not within " + targetPath); 59 | } 60 | return entryPath; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/server/bundle/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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 | @javax.annotation.ParametersAreNonnullByDefault 21 | package org.sonar.css.plugin.server.bundle; 22 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/java/org/sonar/css/plugin/server/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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 | @javax.annotation.ParametersAreNonnullByDefault 21 | package org.sonar.css.plugin.server; 22 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S1116.html: -------------------------------------------------------------------------------- 1 |

Extra semicolons are usually introduced by mistake, for example because:

2 |
    3 |
  • It was meant to be replaced by one more property declaration, but this was forgotten.
  • 4 |
  • There was a typo which lead the semicolon to be doubled, i.e. ;;.
  • 5 |
6 |

See

7 |
    8 |
  • CERT, MSC12-C. - Detect and remove code that has no effect or is never executed 9 |
  • 10 |
  • CERT, MSC51-J. - Do not place a semicolon immediately following an if, for, or while 11 | condition
  • 12 |
  • CERT, EXP15-C. - Do not place a semicolon on the same line as an if, for, or while 13 | statement
  • 14 |
15 | 16 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S1116.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Extra semicolons should be removed", 3 | "type": "CODE_SMELL", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "2min" 8 | }, 9 | "tags": [ 10 | "unused" 11 | ], 12 | "defaultSeverity": "Minor", 13 | "ruleSpecification": "RSPEC-1116", 14 | "sqKey": "S1116", 15 | "scope": "All" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S1128.html: -------------------------------------------------------------------------------- 1 |

Having the import of the same file twice, makes one of them useless. Leaving them in reduces the code's readability, since their presence can be 2 | confusing.

3 |

Noncompliant Code Example

4 |
 5 | @import 'a.css';
 6 | @import 'a.css'; // Noncompliant
 7 | 
 8 | @import url("a.css");
 9 | @import url("a.css"); // Noncompliant
10 | 
11 |

Exceptions

12 |

This rule ignores @import in less files.

13 | 14 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S1128.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Duplicate imports should be removed", 3 | "type": "CODE_SMELL", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "2min" 8 | }, 9 | "tags": [ 10 | "unused" 11 | ], 12 | "defaultSeverity": "Minor", 13 | "ruleSpecification": "RSPEC-1128", 14 | "sqKey": "S1128", 15 | "scope": "All" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4647.html: -------------------------------------------------------------------------------- 1 |

An invalid color definition will by default be interpreted as black, which is likely to have unintended impacts on the expected look and feel of 2 | the website.

3 |

This rule raises an issue when a color definition (color, background-color) is not valid. The color definition is 4 | considered valid when it is made of hexadecimal characters:

5 |
    6 |
  • longhand: 6 or 8 characters (when alpha is defined)
  • 7 |
  • shorthand variant: 3 or 4 characters (when alpha is defined)
  • 8 |
9 |

Noncompliant Code Example

10 |
11 | a {
12 |  color: #3c; /* Noncompliant; shorthand should be made of 3 characters */
13 | }
14 | div {
15 |   background-color: #3cb371a; /* Noncompliant; alpha should have 2 characters */
16 | }
17 | 
18 |

Compliant Solution

19 |
20 | a {
21 |  color: #3cc;
22 | }
23 | div {
24 |   background-color: #3cb371ac;
25 | }
26 | 
27 |

See

28 | 31 | 32 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4647.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Color definitions should be valid", 3 | "type": "BUG", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "1min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Blocker", 13 | "ruleSpecification": "RSPEC-4647", 14 | "sqKey": "S4647", 15 | "scope": "All" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4648.html: -------------------------------------------------------------------------------- 1 |

Having duplicated font names doesn't help to read the font declaration and may be an indicator the author of the line was not sure how to configure 2 | it. This rule raises an issue when font or font-family properties contain a duplicated font name. This rule ignores 3 | $sass, @less, and var(--custom-property) variable syntaxes.

4 |

Noncompliant Code Example

5 |
 6 | a {
 7 |   font-family: 'Georgia', Georgia, serif; /* Noncompliant; 'Georgia' is duplicated */
 8 | }
 9 | 
10 |

Compliant Solution

11 |
12 | a {
13 |   font-family: Georgia, serif;
14 | }
15 | 
16 | 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4648.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Duplicated font names should be removed", 3 | "type": "CODE_SMELL", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "1min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Major", 13 | "ruleSpecification": "RSPEC-4648", 14 | "sqKey": "S4648", 15 | "scope": "All" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4649.html: -------------------------------------------------------------------------------- 1 |

If none of the font names defined in a font or font-family declaration are available on the browser of the user, the 2 | browser will display the text using its default font. It's recommended to always define a generic font family for each declaration of 3 | font or font-family to get a less degraded situation than relying on the default browser font. All browsers should implement 4 | a list of generic font matching these families: Serif, Sans-serif, cursive, fantasy, 5 | Monospace.

6 |

Noncompliant Code Example

7 |
 8 | a {
 9 |   font-family: Helvetica, Arial, Verdana, Tahoma; /* Noncompliant; there is no generic font family in the list */
10 | }
11 | 
12 |

Compliant Solution

13 |
14 | a {
15 |   font-family: Helvetica, Arial, Verdana, Tahoma, sans-serif;
16 | }
17 | 
18 |

See

19 | 22 | 23 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4649.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Font declarations should contain at least one generic font family", 3 | "type": "BUG", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "1min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Major", 13 | "ruleSpecification": "RSPEC-4649", 14 | "sqKey": "S4649", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4650.html: -------------------------------------------------------------------------------- 1 |

calc is a CSS3 function that provides the possibility to do simple math in CSS (add, subtract, divide, multiply). Without spaces 2 | around operators, calc will have no effect.

3 |

More precisely, before an operator, there must be a single whitespace or a newline plus indentation. After an operator, there must be a single 4 | whitespace or a newline.

5 |

Noncompliant Code Example

6 |
 7 | #div1 {
 8 |     position: absolute;
 9 |     width: calc(100%- 100px); /* Noncompliant; no space after the % sign */
10 | }
11 | 
12 |

Compliant Solution

13 |
14 | #div1 {
15 |     position: absolute;
16 |     width: calc(100% - 100px);
17 | }
18 | 
19 | 20 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4650.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "\"calc\" operands should be correctly spaced", 3 | "type": "BUG", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "1min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Blocker", 13 | "ruleSpecification": "RSPEC-4650", 14 | "sqKey": "S4650", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4651.html: -------------------------------------------------------------------------------- 1 |

linear-gradient was standardized with CSS3. Before that, it was possible to use different non-standard values to define the gradient's 2 | direction. Because these values are not standard, they are not supported in all browsers and therefore they should no longer be used in order to get 3 | the expected gradient in the latest browser versions that support CSS3.

4 |

This rule raises an issue when the first parameter of a linear-gradient is not a valid <side-or-corner> or 5 | angle.

6 |

Noncompliant Code Example

7 |
 8 | .foo {
 9 |   background: -webkit-linear-gradient(to top, #fff, #000);
10 |   background: linear-gradient(top, #fff, #000);
11 | }
12 | 
13 | .bar {
14 |   background: linear-gradient(45, #fff, #000);
15 | }
16 | 
17 |

Compliant Solution

18 |
19 | .foo {
20 |   background: -webkit-linear-gradient(top, #fff, #000);
21 |   background: linear-gradient(to top, #fff, #000);
22 | }
23 | 
24 | .bar {
25 |   background: linear-gradient(45deg, #fff, #000);
26 | }
27 | 
28 |

See

29 | 33 | 34 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4651.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "\"linear-gradient\" directions should be valid", 3 | "type": "BUG", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "1min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Critical", 13 | "ruleSpecification": "RSPEC-4651", 14 | "sqKey": "S4651", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4652.html: -------------------------------------------------------------------------------- 1 |

According to the W3C specifications:

2 |
3 |

A string cannot directly contain a newline. To include a newline in a string, use an escape representing the line feed character in ISO-10646 4 | (U+000A), such as "\A" or "\00000a".

5 |

[...]

6 |

It is possible to break strings over several lines, for aesthetic or other reasons, but in such a case the newline itself has to be escaped with 7 | a backslash (\).

8 |
9 |

Noncompliant Code Example

10 |
11 | a {
12 |   content: "first
13 |     second";
14 | }
15 | 
16 |

Compliant Solution

17 |
18 | a {
19 |   content: "first\Asecond";
20 | }
21 | 
22 |

See

23 | 26 | 27 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4652.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Strings should not contain new lines", 3 | "type": "CODE_SMELL", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "1min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Major", 13 | "ruleSpecification": "RSPEC-4652", 14 | "sqKey": "S4652", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4653.html: -------------------------------------------------------------------------------- 1 |

The W3C specifications define the units that can be used with lengths. A unit that is not part of the list of supported ones is likely 2 | to be a typo and will be seen as a UI bug by the user.

3 |

This rule raises an issue each time a unit is not officially supported.

4 |

Noncompliant Code Example

5 |
 6 | a {
 7 |   width: 10pixels; /* Noncompliant; "pixels" is not a valid unit */
 8 | }
 9 | 
10 |

Compliant Solution

11 |
12 | a {
13 |   width: 10px;
14 | }
15 | 
16 |

See

17 | 20 | 21 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4653.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Units should be valid", 3 | "type": "BUG", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "5min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Blocker", 13 | "ruleSpecification": "RSPEC-4653", 14 | "sqKey": "S4653", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4654.html: -------------------------------------------------------------------------------- 1 |

The W3C specifications define the valid CSS properties. Only the official and browser-specific properties should be used to get the expected impact 2 | in the final rendering.

3 |

This rule ignores:

4 |
    5 |
  • $sass, @less, and var(--custom-property) variable syntaxes.
  • 6 |
  • vendor-prefixed properties (e.g., -moz-align-self, -webkit-align-self).
  • 7 |
8 |

Noncompliant Code Example

9 |
10 | a {
11 |   colour: blue; /* Noncompliant; colour is not part of the specifications */
12 | }
13 | 
14 |

Compliant Solution

15 |
16 | a {
17 |   color: blue;
18 | }
19 | 
20 | 21 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4654.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "CSS properties should be valid", 3 | "type": "BUG", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "5min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Blocker", 13 | "ruleSpecification": "RSPEC-4654", 14 | "sqKey": "S4654", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4655.html: -------------------------------------------------------------------------------- 1 |

!important within keyframes declarations is completely ignored in some browsers and therefore it should not be used to be consistent 2 | among all browsers.

3 |

Noncompliant Code Example

4 |
 5 | @keyframes kf {
 6 |   from { margin-top: 50px; }
 7 |   50%  { margin-top: 150px !important; } /* Noncompliant; ignored */
 8 |   to   { margin-top: 100px; }
 9 | }
10 | 
11 |

Compliant Solution

12 |
13 | @keyframes kf {
14 |   from { margin-top: 50px; }
15 |   50%  { margin-top: 150px; }
16 |   to   { margin-top: 100px; }
17 | }
18 | 
19 |

See

20 | 24 | 25 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4655.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "\"!important\" should not be used on \"keyframes\"", 3 | "type": "BUG", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "1min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Major", 13 | "ruleSpecification": "RSPEC-4655", 14 | "sqKey": "S4655", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4656.html: -------------------------------------------------------------------------------- 1 |

CSS allows duplicate property names but only the last instance of a duplicated name determines the actual value that will be used for it. 2 | Therefore, changing values of other occurrences of a duplicated name will have no effect and may cause misunderstandings and bugs.

3 |

This rule ignores $sass, @less, and var(--custom-property) variable syntaxes.

4 |

Noncompliant Code Example

5 |
 6 | a {
 7 |   color: pink;
 8 |   background: orange;
 9 |   color: orange
10 | }
11 | 
12 |

Compliant Solution

13 |
14 | a {
15 |   color: pink;
16 |   background: orange
17 | }
18 | 
19 | 20 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4656.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Properties should not be duplicated", 3 | "type": "BUG", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "1min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Major", 13 | "ruleSpecification": "RSPEC-4656", 14 | "sqKey": "S4656", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4657.html: -------------------------------------------------------------------------------- 1 |

A shorthand property defined after a longhand property will completely override the value defined in the longhand property making the longhand one 2 | useless. The code should be refactored to consider the longhand property or to remove it completely.

3 |

Noncompliant Code Example

4 |
 5 | a {
 6 |   padding-left: 10px;
 7 |   padding: 20px; /* Noncompliant; padding is overriding padding-left making it useless */
 8 | }
 9 | 
10 |

Compliant Solution

11 |
12 | a {
13 |   padding: 10px; /* Compliant; padding is defining a general behaviour and padding-left, just after, is precising the left case */
14 |   padding-left: 20px;
15 | }
16 | 
17 |

See

18 | 22 | 23 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4657.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Shorthand properties that override related longhand properties should be avoided", 3 | "type": "BUG", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "5min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Critical", 13 | "ruleSpecification": "RSPEC-4657", 14 | "sqKey": "S4657", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4658.html: -------------------------------------------------------------------------------- 1 |

Leftover empty blocks are usually introduced by mistake. They are useless and prevent readability of the code. They should be removed or completed 2 | with real code.

3 |

Noncompliant Code Example

4 |
 5 | a { }
 6 | 
7 |

Compliant Solution

8 |
 9 | a { color: pink; }
10 | 
11 | 12 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4658.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Empty blocks should be removed", 3 | "type": "CODE_SMELL", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "1min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Major", 13 | "ruleSpecification": "RSPEC-4658", 14 | "sqKey": "S4658", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4659.html: -------------------------------------------------------------------------------- 1 |

The W3C specifications define the valid pseudo-class selectors. Only the official and browser-specific pseudo-class selectors should be used to get 2 | the expected impact in the final rendering.

3 |

Noncompliant Code Example

4 |
 5 | a:hoverr { /* Noncompliant; there is a typo on the word "hover" */
 6 | ...
 7 | }
 8 | 
9 |

Compliant Solution

10 |
11 | a:hover {
12 | ...
13 | }
14 | 
15 | 16 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4659.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Pseudo-class selectors should be valid", 3 | "type": "BUG", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "1min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Major", 13 | "ruleSpecification": "RSPEC-4659", 14 | "sqKey": "S4659", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4660.html: -------------------------------------------------------------------------------- 1 |

The W3C specifications define the valid pseudo-element selectors. Only the official and browser-specific pseudo-element selectors should be used to 2 | get the expected impact in the final rendering.

3 |

Noncompliant Code Example

4 |
 5 | a::beforre { /* Noncompliant; there is a typo on the word "before" */
 6 | ...
 7 | }
 8 | 
9 |

Compliant Solution

10 |
11 | a::before {
12 | ...
13 | }
14 | 
15 | 16 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4660.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Pseudo-element selectors should be valid", 3 | "type": "BUG", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "1min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Major", 13 | "ruleSpecification": "RSPEC-4660", 14 | "sqKey": "S4660", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4661.html: -------------------------------------------------------------------------------- 1 |

The W3C specifications define the valid media features. Only the official and browser-specific media features should be used to get the expected 2 | impact in the final rendering.

3 |

Noncompliant Code Example

4 |
 5 | @media screen and (unknown: 1000px) { .. }
 6 | 
7 |

Compliant Solution

8 |
 9 | @media screen and (width: 1000px) { .. }
10 | 
11 |

See

12 | 15 | 16 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4661.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Media features should be valid", 3 | "type": "BUG", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "1min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Major", 13 | "ruleSpecification": "RSPEC-4661", 14 | "sqKey": "S4661", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4662.html: -------------------------------------------------------------------------------- 1 |

The W3C specifications define the valid at-rules. Only the official and browser-specific at-rules should be used to get 2 | the expected impact in the final rendering.

3 |

Noncompliant Code Example

4 |
 5 | @encoding "utf-8";
 6 | 
7 |

Compliant Solution

8 |
 9 | @charset "utf-8";
10 | 
11 | 12 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4662.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "\"at-rules\" should be valid", 3 | "type": "BUG", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "1min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Major", 13 | "ruleSpecification": "RSPEC-4662", 14 | "sqKey": "S4662", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4663.html: -------------------------------------------------------------------------------- 1 |

An empty multi-line comment is likely to be a mistake and doesn't help to improve the readability of the code. For these reasons, it should be 2 | removed.

3 |

Noncompliant Code Example

4 |
 5 | /* */
 6 | 
 7 | /*
 8 | 
 9 |  */
10 | 
11 | 12 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4663.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Multi-line comments should not be empty", 3 | "type": "CODE_SMELL", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "1min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Minor", 13 | "ruleSpecification": "RSPEC-4663", 14 | "sqKey": "S4663", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4664.html: -------------------------------------------------------------------------------- 1 |

Order of instructions in CSS is important: instructions with equal specificity that occur later in the file take the priority. But when a selector 2 | with a higher specificity (e.g. p a { color: green;}) comes before the selector it overrides (e.g.: a { color: green;}), the 3 | priority is given to the first one. Even if it works properly, this is harder to anticipate the behaviour of the stylesheet while reading as it goes 4 | against the principle that the last instruction takes the priority.

5 |

Noncompliant Code Example

6 |
 7 | p a {
 8 |   color: green;
 9 | }
10 | 
11 | a {
12 |   color: blue;
13 | }
14 | 
15 |

Compliant Solution

16 |
17 | a {
18 |   color: blue;
19 | }
20 | 
21 | p a {
22 |   color: green;
23 | }
24 | 
25 | 26 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4664.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Selectors of lower specificity should come before overriding selectors of higher specificity", 3 | "type": "CODE_SMELL", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "5min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Critical", 13 | "ruleSpecification": "RSPEC-4664", 14 | "sqKey": "S4664", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4666.html: -------------------------------------------------------------------------------- 1 |

Duplication of selectors might indicate a copy-paste mistake. The rule detects the following kinds of duplications:

2 |
    3 |
  • within a list of selectors in a single rule set
  • 4 |
  • for duplicated selectors in different rule sets within a single stylesheet.
  • 5 |
6 |

Noncompliant Code Example

7 |
 8 | .foo, .bar, .foo { ... }  /* Noncompliant */
 9 | 
10 | .class1 { ... }
11 | .class1 { ... }  /* Noncompliant */
12 | 
13 |

Compliant Solution

14 |
15 | .foo, .bar { ... }
16 | 
17 | .class1 { ... }
18 | .class2 { ... }
19 | 
20 | 21 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4666.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Selectors should not be duplicated", 3 | "type": "CODE_SMELL", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "1min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Major", 13 | "ruleSpecification": "RSPEC-4666", 14 | "sqKey": "S4666", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4667.html: -------------------------------------------------------------------------------- 1 |

This rule raises an issue when a CSS file is empty (ie: containing only spaces).

2 | 3 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4667.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "CSS files should not be empty", 3 | "type": "CODE_SMELL", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "1min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Major", 13 | "ruleSpecification": "RSPEC-4667", 14 | "sqKey": "S4667", 15 | "scope": "All" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4668.html: -------------------------------------------------------------------------------- 1 |

The W3C specifications say comments should be defined using /* ... */. The use of // is not supported on all browsers and 2 | can lead to unexpected results.

3 |

Noncompliant Code Example

4 |
 5 | // some comment
 6 | a { color: pink; }
 7 | 
8 |

Compliant Solution

9 |
10 | /* some comment */
11 | a { color: pink; }
12 | 
13 |

Exceptions

14 |

This rule ignores single line comments in less and scss files.

15 | 16 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4668.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Single line comment syntax should not be used", 3 | "type": "BUG", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "1min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Blocker", 13 | "ruleSpecification": "RSPEC-4668", 14 | "sqKey": "S4668", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4670.html: -------------------------------------------------------------------------------- 1 |

HTML, SVG, and MathML define the selectors which can be used in a CSS. A selector that is not part of them is likely to be a typo or a 2 | misunderstanding of the CSS syntax.

3 |

Noncompliant Code Example

4 |
 5 | field {}
 6 | 
 7 | ul list {}
 8 | 
9 |

Compliant Solution

10 |
11 | input {}
12 | 
13 | ul li {}
14 | 
15 | 16 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4670.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Selectors should be known", 3 | "type": "BUG", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "5min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Critical", 13 | "ruleSpecification": "RSPEC-4670", 14 | "sqKey": "S4670", 15 | "scope": "Main" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S5362.html: -------------------------------------------------------------------------------- 1 |

To perform calculations when specifying a CSS property calc() function can be used. This function takes single expression as 2 | parameter. When writing this expression some rules must be respected:

3 |
    4 |
  • no empty calc()
  • 5 |
  • there should be an operator between the arguments, spacing should be respected
  • 6 |
  • there should not be any division by zero
  • 7 |
  • the resolved type should be valid for where the expression is placed
  • 8 |
9 |

Otherwise calc() function will be invalid and the entire rule using it will be ignored.

10 |

Noncompliant Code Example

11 |
12 | .btn {
13 |   border: solid black 1px;
14 |   width: calc(100% 80px);  /* Noncompliant */
15 | }
16 | 
17 |

Compliant Solution

18 |
19 | .btn {
20 |   border: solid black 1px;
21 |   width: calc(100% - 80px);
22 | }
23 | 
24 | 25 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S5362.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Expressions within \"calc\" should be valid", 3 | "type": "BUG", 4 | "status": "ready", 5 | "remediation": { 6 | "func": "Constant\/Issue", 7 | "constantCost": "5min" 8 | }, 9 | "tags": [ 10 | 11 | ], 12 | "defaultSeverity": "Critical", 13 | "ruleSpecification": "RSPEC-5362", 14 | "sqKey": "S5362", 15 | "scope": "All" 16 | } 17 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/Sonar_way_profile.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Sonar way", 3 | "ruleKeys": [ 4 | "S1116", 5 | "S1128", 6 | "S4647", 7 | "S4648", 8 | "S4649", 9 | "S4651", 10 | "S4652", 11 | "S4653", 12 | "S4654", 13 | "S4655", 14 | "S4656", 15 | "S4657", 16 | "S4658", 17 | "S4659", 18 | "S4660", 19 | "S4661", 20 | "S4662", 21 | "S4663", 22 | "S4666", 23 | "S4667", 24 | "S4668", 25 | "S4670", 26 | "S5362" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/main/resources/static/documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CSS 3 | key: css 4 | --- 5 | 6 | 7 | 8 | 9 | 10 | 11 | ## Prerequisites 12 | In order to analyze CSS code, you need to have Node.js >= 8 installed on the machine running the scan. Set property `sonar.nodejs.executable` to an absolute path to Node.js executable, if standard `node` is not available. 13 | 14 | If you have a community plugin that handles CSS installed on your SonarQube instance it will conflict with analysis of CSS, so it should be removed. 15 | 16 | ## Language-Specific Properties 17 | 18 | Discover and update the CSS-specific [properties](/analysis/analysis-parameters/) in: Project **[Administration > General Settings > CSS](/#sonarqube-admin#/admin/settings?category=css)** 19 | 20 | ## Supported Languages 21 | * CSS, SCSS, Less 22 | * Also 'style' inside PHP, HTML and VueJS files 23 | 24 | ## Related Pages 25 | * [Importing External Issues](/analysis/external-issues/) (StyleLint.io) 26 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/sonarcss-assembly.xml: -------------------------------------------------------------------------------- 1 | 4 | sonarcss-assembly 5 | 6 | zip 7 | 8 | false 9 | 10 | 11 | css-bundle 12 | 13 | lib/**/* 14 | 15 | package/**/* 16 | bin/**/* 17 | node_modules/**/* 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssLanguageTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin; 21 | 22 | import org.junit.Test; 23 | import org.sonar.api.config.internal.MapSettings; 24 | 25 | import static org.assertj.core.api.Assertions.assertThat; 26 | 27 | public class CssLanguageTest { 28 | 29 | @Test 30 | public void test() { 31 | MapSettings settings = new MapSettings(); 32 | settings.setProperty(CssPlugin.FILE_SUFFIXES_KEY, CssPlugin.FILE_SUFFIXES_DEFVALUE); 33 | CssLanguage language = new CssLanguage(settings.asConfig()); 34 | assertThat(language.getKey()).isEqualTo("css"); 35 | assertThat(language.getName()).isEqualTo("CSS"); 36 | assertThat(language.getFileSuffixes()).containsOnly(".css", ".less", ".scss"); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssPluginTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin; 21 | 22 | import org.junit.Test; 23 | import org.sonar.api.Plugin; 24 | import org.sonar.api.SonarEdition; 25 | import org.sonar.api.SonarQubeSide; 26 | import org.sonar.api.SonarRuntime; 27 | import org.sonar.api.internal.SonarRuntimeImpl; 28 | import org.sonar.api.utils.Version; 29 | 30 | import static org.assertj.core.api.Assertions.assertThat; 31 | 32 | public class CssPluginTest { 33 | 34 | @Test 35 | public void count_extensions() { 36 | SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.create(7, 9), SonarQubeSide.SCANNER, SonarEdition.COMMUNITY); 37 | Plugin.Context context = new Plugin.Context(runtime); 38 | Plugin underTest = new CssPlugin(); 39 | underTest.define(context); 40 | assertThat(context.getExtensions()).hasSize(12); 41 | } 42 | 43 | @Test 44 | public void count_extensions_sonarlint() { 45 | SonarRuntime runtime = SonarRuntimeImpl.forSonarLint(Version.create(7, 9)); 46 | Plugin.Context context = new Plugin.Context(runtime); 47 | Plugin underTest = new CssPlugin(); 48 | underTest.define(context); 49 | assertThat(context.getExtensions()).hasSize(12); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssRulesDefinitionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin; 21 | 22 | import org.junit.Test; 23 | import org.sonar.api.server.rule.RulesDefinition; 24 | 25 | import static org.assertj.core.api.Assertions.assertThat; 26 | 27 | public class CssRulesDefinitionTest { 28 | 29 | @Test 30 | public void test_with_external_rules() { 31 | CssRulesDefinition rulesDefinition = new CssRulesDefinition(); 32 | RulesDefinition.Context context = new RulesDefinition.Context(); 33 | rulesDefinition.define(context); 34 | 35 | assertThat(context.repositories()).hasSize(2); 36 | RulesDefinition.Repository mainRepository = context.repository("css"); 37 | RulesDefinition.Repository externalRepository = context.repository("external_stylelint"); 38 | 39 | assertThat(externalRepository.name()).isEqualTo("stylelint"); 40 | assertThat(externalRepository.language()).isEqualTo("css"); 41 | assertThat(externalRepository.isExternal()).isEqualTo(true); 42 | assertThat(externalRepository.rules()).hasSize(170); 43 | 44 | assertThat(mainRepository.name()).isEqualTo("SonarAnalyzer"); 45 | assertThat(mainRepository.language()).isEqualTo("css"); 46 | assertThat(mainRepository.isExternal()).isEqualTo(false); 47 | assertThat(mainRepository.rules()).hasSize(CssRules.getRuleClasses().size()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/java/org/sonar/css/plugin/MinifiedFilesFilterTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin; 21 | 22 | import org.junit.Test; 23 | import org.sonar.api.batch.fs.internal.DefaultInputFile; 24 | import org.sonar.api.batch.fs.internal.TestInputFileBuilder; 25 | 26 | import static org.assertj.core.api.Assertions.assertThat; 27 | 28 | public class MinifiedFilesFilterTest { 29 | 30 | private static final MinifiedFilesFilter MINIFIED_FILES_FILTER = new MinifiedFilesFilter(); 31 | 32 | @Test 33 | public void should_exclude_by_name() throws Exception { 34 | DefaultInputFile jsFile = TestInputFileBuilder.create("", "foo.min.css") 35 | .setLanguage("css") 36 | .setContents("short content") 37 | .build(); 38 | assertThat(MINIFIED_FILES_FILTER.accept(jsFile)).isFalse(); 39 | } 40 | 41 | @Test 42 | public void should_keep_other_lang() throws Exception { 43 | DefaultInputFile jsFile = TestInputFileBuilder.create("", "foo.min.css").setLanguage("js").build(); 44 | assertThat(MINIFIED_FILES_FILTER.accept(jsFile)).isTrue(); 45 | } 46 | 47 | @Test 48 | public void should_exclude_by_content() throws Exception { 49 | String longContent = new String(new char[500]).replace("\0", "a") + "\n"; 50 | 51 | DefaultInputFile jsFile = TestInputFileBuilder.create("", "foo.css") 52 | .setLanguage("css") 53 | .setContents(longContent) 54 | .build(); 55 | assertThat(MINIFIED_FILES_FILTER.accept(jsFile)).isFalse(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/java/org/sonar/css/plugin/SonarWayProfileTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin; 21 | 22 | import org.junit.Test; 23 | import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.BuiltInQualityProfile; 24 | import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.Context; 25 | 26 | import static org.assertj.core.api.Assertions.assertThat; 27 | 28 | public class SonarWayProfileTest { 29 | 30 | @Test 31 | public void should_create_sonar_way_profile() { 32 | SonarWayProfile definition = new SonarWayProfile(); 33 | Context context = new Context(); 34 | definition.define(context); 35 | 36 | BuiltInQualityProfile profile = context.profile("css", SonarWayProfile.PROFILE_NAME); 37 | 38 | assertThat(profile.language()).isEqualTo(CssLanguage.KEY); 39 | assertThat(profile.name()).isEqualTo(SonarWayProfile.PROFILE_NAME); 40 | assertThat(profile.rules()).extracting("repoKey").containsOnly(CssRulesDefinition.REPOSITORY_KEY); 41 | // org.sonar.css.plugin.rules.FunctionCalcNoUnspacedOperator is not part of SonarWay 42 | assertThat(profile.rules()).extracting("ruleKey").hasSize(CssRules.getRuleClasses().size() - 2); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/java/org/sonar/css/plugin/TestActiveRules.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin; 21 | 22 | import java.util.Arrays; 23 | import java.util.Collection; 24 | import java.util.Collections; 25 | import java.util.List; 26 | import java.util.Map; 27 | import java.util.stream.Collectors; 28 | import javax.annotation.CheckForNull; 29 | import org.sonar.api.batch.rule.ActiveRule; 30 | import org.sonar.api.batch.rule.ActiveRules; 31 | import org.sonar.api.rule.RuleKey; 32 | 33 | public class TestActiveRules implements ActiveRules { 34 | 35 | private final List activeRules; 36 | 37 | public TestActiveRules(String... activeRules) { 38 | this.activeRules = Arrays.stream(activeRules).map(TestActiveRule::new).collect(Collectors.toList()); 39 | } 40 | 41 | @CheckForNull 42 | @Override 43 | public ActiveRule find(RuleKey ruleKey) { 44 | return null; 45 | } 46 | 47 | @Override 48 | public Collection findAll() { 49 | return activeRules; 50 | } 51 | 52 | @Override 53 | public Collection findByRepository(String repository) { 54 | return activeRules; 55 | } 56 | 57 | @Override 58 | public Collection findByLanguage(String language) { 59 | return activeRules; 60 | } 61 | 62 | @CheckForNull 63 | @Override 64 | public ActiveRule findByInternalKey(String repository, String internalKey) { 65 | return null; 66 | } 67 | 68 | class TestActiveRule implements ActiveRule { 69 | 70 | final RuleKey ruleKey; 71 | 72 | public TestActiveRule(String key) { 73 | ruleKey = RuleKey.of(CssRulesDefinition.REPOSITORY_KEY, key); 74 | } 75 | 76 | @Override 77 | public RuleKey ruleKey() { 78 | return ruleKey; 79 | } 80 | 81 | @Override 82 | public String severity() { 83 | return null; 84 | } 85 | 86 | @Override 87 | public String language() { 88 | return null; 89 | } 90 | 91 | @CheckForNull 92 | @Override 93 | public String param(String key) { 94 | return null; 95 | } 96 | 97 | @Override 98 | public Map params() { 99 | return Collections.emptyMap(); 100 | } 101 | 102 | @CheckForNull 103 | @Override 104 | public String internalKey() { 105 | return null; 106 | } 107 | 108 | @CheckForNull 109 | @Override 110 | public String templateRuleKey() { 111 | return null; 112 | } 113 | 114 | @Override 115 | public String qpKey() { 116 | return null; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/java/org/sonar/css/plugin/server/NetUtilsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.server; 21 | 22 | import java.io.IOException; 23 | import org.junit.Test; 24 | 25 | import static org.assertj.core.api.Assertions.assertThat; 26 | 27 | public class NetUtilsTest { 28 | 29 | @Test 30 | public void findOpenPort_should_not_return_zero() throws IOException { 31 | assertThat(NetUtils.findOpenPort()) 32 | .isGreaterThan(0) 33 | .isLessThanOrEqualTo(65535); 34 | } 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/java/org/sonar/css/plugin/server/bundle/CssAnalyzerBundleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.server.bundle; 21 | 22 | import java.io.File; 23 | import java.nio.charset.StandardCharsets; 24 | import java.nio.file.Files; 25 | import java.nio.file.Path; 26 | import java.nio.file.Paths; 27 | import org.junit.Rule; 28 | import org.junit.Test; 29 | import org.sonar.api.utils.internal.JUnitTempFolder; 30 | 31 | import static org.assertj.core.api.Assertions.assertThat; 32 | import static org.assertj.core.api.Assertions.assertThatCode; 33 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 34 | 35 | public class CssAnalyzerBundleTest { 36 | 37 | @Rule 38 | public JUnitTempFolder tempFolder = new JUnitTempFolder(); 39 | 40 | @Test 41 | public void default_css_bundle_location() throws Exception { 42 | CssAnalyzerBundle bundle = new CssAnalyzerBundle(); 43 | assertThat(bundle.bundleLocation).isEqualTo("/css-bundle.zip"); 44 | } 45 | 46 | @Test 47 | public void almost_empty_css_bundle() throws Exception { 48 | Bundle bundle = new CssAnalyzerBundle("/bundle/test-css-bundle.zip"); 49 | Path deployLocation = tempFolder.newDir().toPath(); 50 | String expectedStartServer = deployLocation.resolve(Paths.get("css-bundle", "bin", "server")).toString(); 51 | bundle.deploy(deployLocation); 52 | String script = bundle.startServerScript(); 53 | assertThat(script).isEqualTo(expectedStartServer); 54 | File scriptFile = new File(script); 55 | assertThat(scriptFile).exists(); 56 | String content = new String(Files.readAllBytes(scriptFile.toPath()), StandardCharsets.UTF_8); 57 | assertThat(content).startsWith("#!/usr/bin/env node"); 58 | } 59 | 60 | @Test 61 | public void missing_bundle() throws Exception { 62 | Bundle bundle = new CssAnalyzerBundle("/bundle/invalid-bundle-path.zip"); 63 | assertThatThrownBy(() -> bundle.deploy(tempFolder.newDir().toPath())) 64 | .isInstanceOf(IllegalStateException.class) 65 | .hasMessage("css-bundle not found in /bundle/invalid-bundle-path.zip"); 66 | } 67 | 68 | @Test 69 | public void invalid_bundle_zip() throws Exception { 70 | Bundle bundle = new CssAnalyzerBundle("/bundle/invalid-zip-file.zip"); 71 | assertThatThrownBy(() -> bundle.deploy(tempFolder.newDir().toPath())) 72 | .isInstanceOf(IllegalStateException.class) 73 | .hasMessage("Failed to deploy css-bundle (with classpath '/bundle/invalid-zip-file.zip')"); 74 | } 75 | 76 | @Test 77 | public void should_not_fail_when_deployed_twice() throws Exception { 78 | Bundle bundle = new CssAnalyzerBundle("/bundle/test-css-bundle.zip"); 79 | Path deployLocation = tempFolder.newDir().toPath(); 80 | assertThatCode(() -> { 81 | bundle.deploy(deployLocation); 82 | bundle.deploy(deployLocation); 83 | }).doesNotThrowAnyException(); 84 | } 85 | 86 | @Test 87 | public void test_resolve() { 88 | Bundle bundle = new CssAnalyzerBundle("/bundle/test-css-bundle.zip"); 89 | Path deployLocation = tempFolder.newDir().toPath(); 90 | bundle.deploy(deployLocation); 91 | assertThat(bundle.resolve("relative/path")) 92 | .contains("css-bundle") 93 | .endsWith("path") 94 | .startsWith(deployLocation.toString()); 95 | 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/java/org/sonar/css/plugin/server/bundle/ZipTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarCSS 3 | * Copyright (C) 2018-2021 SonarSource SA 4 | * mailto:info AT sonarsource DOT 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.plugin.server.bundle; 21 | 22 | import java.nio.file.Files; 23 | import java.nio.file.Path; 24 | import java.util.zip.ZipEntry; 25 | import java.util.zip.ZipOutputStream; 26 | import org.junit.Rule; 27 | import org.junit.Test; 28 | import org.sonar.api.utils.internal.JUnitTempFolder; 29 | 30 | import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; 31 | import static org.assertj.core.api.Java6Assertions.assertThat; 32 | 33 | public class ZipTest { 34 | 35 | @Rule 36 | public JUnitTempFolder tempFolder = new JUnitTempFolder(); 37 | 38 | @Test 39 | public void test() throws Exception { 40 | Path zipFile = tempFolder.newFile().toPath(); 41 | try (ZipOutputStream zout = new ZipOutputStream(Files.newOutputStream(zipFile))) { 42 | ZipEntry dir = new ZipEntry("dir/"); 43 | zout.putNextEntry(dir); 44 | zout.closeEntry(); 45 | ZipEntry zipEntry = new ZipEntry("dir/file.txt"); 46 | zout.putNextEntry(zipEntry); 47 | zout.write("Hello World".getBytes()); 48 | zout.closeEntry(); 49 | } 50 | Path out = tempFolder.newDir().toPath(); 51 | Zip.extract(Files.newInputStream(zipFile), out); 52 | assertThat(out.resolve("dir/file.txt").toFile()).hasContent("Hello World"); 53 | } 54 | 55 | @Test 56 | public void test_empty_zip() throws Exception { 57 | Path zipFile = tempFolder.newFile().toPath(); 58 | try (ZipOutputStream zout = new ZipOutputStream(Files.newOutputStream(zipFile))) { 59 | 60 | } 61 | Path out = tempFolder.newDir().toPath(); 62 | assertThatThrownBy(() -> Zip.extract(Files.newInputStream(zipFile), out)) 63 | .isInstanceOf(IllegalStateException.class) 64 | .hasMessage("At least one entry expected."); 65 | } 66 | 67 | @Test 68 | public void test_invalid_entry() throws Exception { 69 | Path zipFile = tempFolder.newFile().toPath(); 70 | try (ZipOutputStream zout = new ZipOutputStream(Files.newOutputStream(zipFile))) { 71 | ZipEntry zipEntry = new ZipEntry("../file.txt"); 72 | zout.putNextEntry(zipEntry); 73 | zout.write("Hello World".getBytes()); 74 | zout.closeEntry(); 75 | } 76 | Path out = tempFolder.newDir().toPath(); 77 | assertThatThrownBy(() -> Zip.extract(Files.newInputStream(zipFile), out)) 78 | .isInstanceOf(IllegalStateException.class) 79 | .hasMessage("Archive entry ../file.txt is not within " + out); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/resources/bundle/invalid-zip-file.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonarSource/sonar-css/0885b299dc850766eae254cebc6d8de85f4957ab/sonar-css-plugin/src/test/resources/bundle/invalid-zip-file.zip -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/resources/bundle/test-css-bundle.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonarSource/sonar-css/0885b299dc850766eae254cebc6d8de85f4957ab/sonar-css-plugin/src/test/resources/bundle/test-css-bundle.zip -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/resources/mock-start-server/failedClose.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const http = require('http'); 4 | const port = process.argv[2]; 5 | 6 | const requestHandler = (request, response) => { 7 | let data = []; 8 | request.on('data', chunk => { 9 | data.push(chunk); 10 | }); 11 | if (request.url === '/status') { 12 | response.writeHead(200, {'Content-Type': 'text/plain'}); 13 | response.end('OK!'); 14 | } else { 15 | throw "Failure"; 16 | } 17 | }; 18 | 19 | const server = http.createServer(requestHandler); 20 | 21 | server.listen(port, (err) => { 22 | if (err) { 23 | return console.log('something bad happened', err) 24 | } 25 | 26 | console.log(`server is listening on ${port}`) 27 | }); 28 | 29 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/resources/mock-start-server/startServer.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const http = require('http'); 4 | const port = process.argv[2]; 5 | 6 | const requestHandler = (request, response) => { 7 | let data = []; 8 | request.on('data', chunk => { 9 | data.push(chunk); 10 | }); 11 | request.on('end', () => { 12 | let fileName = null; 13 | let fileContent = null; 14 | if (data.length > 0) { 15 | const analysisRequest = JSON.parse(data.join()); 16 | fileName = analysisRequest.filePath.replace(/.*[\/\\]/g,""); 17 | fileContent = analysisRequest.fileContent; 18 | } 19 | if (request.url === '/status') { 20 | response.writeHead(200, { 'Content-Type': 'text/plain' }); 21 | response.end('OK!'); 22 | } else { 23 | switch (fileName) { 24 | case "file.css": 25 | case "file.web": 26 | case "file.php": 27 | case "file.vue": 28 | case "file.js": // to test that we will not save this issue even if it's provided by response 29 | response.end(JSON.stringify([ 30 | {line: 2, rule: "block-no-empty", text: "Unexpected empty block"} 31 | ])); 32 | break; 33 | case "file-with-rule-id-message.css": 34 | response.end(JSON.stringify([ 35 | {line: 2, rule: "color-no-invalid-hex", text: "some message (color-no-invalid-hex)"} 36 | ])); 37 | break; 38 | case "empty.css": 39 | response.end(JSON.stringify([])); 40 | break; 41 | case "syntax-error.css": 42 | case "syntax-error.web": 43 | response.end(JSON.stringify([ 44 | {line: 2, rule: "CssSyntaxError", text: "Missed semicolon (CssSyntaxError)"} 45 | ])); 46 | break; 47 | case "unknown-rule.css": 48 | response.end(JSON.stringify([ 49 | {line: 2, rule: "unknown-rule-key", text: "some message"} 50 | ])); 51 | break; 52 | case "invalid-json-response.css": 53 | response.end("["); 54 | break; 55 | case "copy-file-content-into-issue-message.css": 56 | response.end(JSON.stringify([ 57 | {line: 1, rule: "block-no-empty", text: "" + fileContent} 58 | ])); 59 | break; 60 | default: 61 | throw "Unexpected fileName: " + fileName; 62 | } 63 | } 64 | }); 65 | }; 66 | 67 | const server = http.createServer(requestHandler); 68 | 69 | server.listen(port, (err) => { 70 | if (err) { 71 | return console.log('something bad happened', err) 72 | } 73 | 74 | console.log(`server is listening on ${port}`) 75 | }); 76 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/resources/mock-start-server/testLogs.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const http = require('http'); 4 | const port = process.argv[2]; 5 | 6 | console.log(`DEBUG testing debug log`) 7 | console.log(`WARN testing warn log`) 8 | console.log(`testing info log`) 9 | console.error(`testing error log`) 10 | 11 | 12 | const server = http.createServer(() => {}); 13 | 14 | server.listen(port, (err) => { 15 | if (err) { 16 | return console.log('something bad happened', err) 17 | } 18 | 19 | console.log(`server is listening on ${port}`) 20 | }); 21 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/resources/mock-start-server/throw.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | throw "Something wrong happened" 4 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/resources/stylelint-report/file.css: -------------------------------------------------------------------------------- 1 | File content is set in test file 2 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/resources/stylelint-report/invalid-file.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "source": "not-exist.css", 4 | "warnings": [ 5 | { 6 | "line": 1, 7 | "rule": "color-no-invalid-hex", 8 | "text": "external issue message" 9 | } 10 | ] 11 | }, 12 | { 13 | "source": "file.css", 14 | "warnings": [ 15 | { 16 | "line": 1, 17 | "rule": "comment-no-empty", 18 | "text": "external issue message (comment-no-empty)" 19 | } 20 | ] 21 | } 22 | ] 23 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/resources/stylelint-report/report-utf16.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonarSource/sonar-css/0885b299dc850766eae254cebc6d8de85f4957ab/sonar-css-plugin/src/test/resources/stylelint-report/report-utf16.json -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/resources/stylelint-report/report-utf8-bom.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "source": "file.css", 4 | "warnings": [ 5 | { 6 | "line": 1, 7 | "rule": "color-no-invalid-hex", 8 | "text": "external issue message (color-no-invalid-hex)" 9 | }, 10 | { 11 | "line": 1, 12 | "rule": "comment-no-empty", 13 | "text": "external issue message (comment-no-empty)" 14 | } 15 | ] 16 | } 17 | ] 18 | -------------------------------------------------------------------------------- /sonar-css-plugin/src/test/resources/stylelint-report/report.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "source": "file.css", 4 | "warnings": [ 5 | { 6 | "line": 1, 7 | "rule": "color-no-invalid-hex", 8 | "text": "external issue message (color-no-invalid-hex)" 9 | }, 10 | { 11 | "line": 1, 12 | "rule": "comment-no-empty", 13 | "text": "external issue message (comment-no-empty)" 14 | } 15 | ] 16 | } 17 | ] 18 | -------------------------------------------------------------------------------- /sonarpedia.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules-metadata-path": "sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css", 3 | "languages": [ 4 | "CSS" 5 | ], 6 | "latest-update": "2021-03-02T17:22:27.244283200Z", 7 | "options": { 8 | "no-language-in-filenames": true 9 | } 10 | } -------------------------------------------------------------------------------- /third-party-licenses.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | mvn org.codehaus.mojo:license-maven-plugin:aggregate-add-third-party -Dlicense.includedScopes=compile 3 | 4 | cat target/generated-sources/license/THIRD-PARTY.txt 5 | -------------------------------------------------------------------------------- /wss-unified-agent.config: -------------------------------------------------------------------------------- 1 | # WhiteSource documentation https://whitesource.atlassian.net/wiki/spaces/WD/pages/1544880156/Unified+Agent+Configuration+Parameters 2 | 3 | excludes=**/*sources.jar **/*javadoc.jar **/its/sources/** **/its/plugin/projects/** 4 | fileSystemScan=False 5 | resolveAllDependencies=False 6 | 7 | maven.aggregateModules=True 8 | maven.downloadMissingDependencies=False 9 | maven.m2RepositoryPath=.m2/repository 10 | maven.resolveDependencies=True 11 | maven.runPreStep=False 12 | 13 | npm.includeDevDependencies=True 14 | npm.resolveDependencies=True 15 | npm.resolveLockFile=False 16 | npm.runPreStep=False 17 | npm.yarnProject=True 18 | 19 | wss.url=https://saas-eu.whitesourcesoftware.com/agent 20 | 21 | forceUpdate=true 22 | checkPolicies=true 23 | forceUpdate.failBuildOnPolicyViolation=true 24 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | --------------------------------------------------------------------------------