JS-2274 Add SCSS-aware css:S4662 analysis by jdkandersson · Pull Request #7780 · SonarSource/SonarJS · GitHub
Skip to content

JS-2274 Add SCSS-aware css:S4662 analysis - #7780

Draft
jdkandersson wants to merge 14 commits into
masterfrom
fix-s4662-sass
Draft

jdkandersson wants to merge 14 commits into
masterfrom
fix-s4662-sass

Conversation

@jdkandersson

@jdkandersson jdkandersson commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • map Stylelint's CSS rule and stylelint-scss's SCSS-aware rule to css:S4662
  • target plain CSS and SCSS independently, including embedded style blocks
  • preserve the shared supported-tool allowlist and configured exclusions across both bindings
  • keep indented Sass and Less excluded
  • add rule, targeting, embedded-content, transformer, metadata, mapping, and integration coverage

Verification

  • clean npm ci without a postcss-sass patch
  • 99 focused rule, targeting, embedded-content, and transformer tests
  • bridge TypeScript compilation
  • focused formatting and git diff --check
  • Maven integration tests not run locally because Maven is unavailable; fast-test fixtures are included for CI

Related

@hashicorp-vault-sonar-prod

hashicorp-vault-sonar-prod Bot commented Aug 19, 2026

Copy link
Copy Markdown

Comment thread packages/analysis/src/css/linter/issues/transform.ts Outdated
@datadog-sonarsource

This comment has been minimized.

@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Ruling Report

New issues flagged (1 issue)

S4662

custom-css/S4662.scss:3

     1 | @use 'variables'; /* No FP */
     2 | 
>    3 | @@media {
     4 |  display: none;
     5 | }

Ruling passed with these expected-result updates already present in the branch. No fix PR was needed.

Comment thread packages/analysis/src/css/linter/issues/transform.ts Outdated
@jdkandersson jdkandersson changed the title JS-2274 Add Sass-aware css:S4662 analysis JS-2274 Add SCSS-aware css:S4662 analysis Aug 19, 2026
config,
};

await sonarRulesReady;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Edge Case: sonarRulesReady rejection bypasses APIError wrapping

await sonarRulesReady at wrapper.ts:98 sits outside the .catch attached to stylelint.lint(...), so if the module-level ruleReady promise (built from stylelint.rules[UPSTREAM_RULE]) ever rejects, lint() throws a raw error instead of the wrapped APIError.linterError, and the module-level promise can also surface as an unhandled rejection if lint() is never called. This is unlikely for a built-in stylelint rule, but wrapping the await (e.g. try/catch converting to APIError) would keep failure handling consistent.

Was this helpful? React with 👍 / 👎

@gitar-bot

gitar-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown
Code Review 👍 Approved with suggestions 2 resolved / 3 findings

Adds SCSS-aware css:S4662 analysis with independent targeting for plain CSS and SCSS, addressing the Sass filter and warning suppression findings. Consider ensuring the sonarRulesReady rejection wraps APIError properly.

💡 Edge Case: sonarRulesReady rejection bypasses APIError wrapping

📄 packages/analysis/src/css/linter/wrapper.ts:98-107 📄 packages/analysis/src/css/rules/S8757/rule.ts:25-27 📄 packages/analysis/src/css/rules/index.ts:28

await sonarRulesReady at wrapper.ts:98 sits outside the .catch attached to stylelint.lint(...), so if the module-level ruleReady promise (built from stylelint.rules[UPSTREAM_RULE]) ever rejects, lint() throws a raw error instead of the wrapped APIError.linterError, and the module-level promise can also surface as an unhandled rejection if lint() is never called. This is unlikely for a built-in stylelint rule, but wrapping the await (e.g. try/catch converting to APIError) would keep failure handling consistent.

✅ 2 resolved
Edge Case: Sass filter suppresses warnings when block source range is incomplete

📄 packages/analysis/src/css/linter/issues/transform.ts:121-135
isOutsideSassEmbeddedBlock returns true (suppress) by default when no embedded block's source range matches the warning position — including the case where a real Sass block has a missing/partial start/end position (isWithinSourceRange returns false). This is the opposite of the CSS-only path (isInNonCssEmbeddedBlock), which keeps the warning in that situation (see the test 'does not suppress warnings when a non-CSS block has no explicit end position'). The result is a potential false negative: a legitimate scss/at-rule-no-unknown issue inside a Sass block could be silently dropped if position metadata is incomplete. Consider defaulting to keep (return false) when no block matches, or add coverage for an incomplete-source Sass block to confirm the intended behavior.

Edge Case: Sass-only warning inside a complete non-Sass block not suppressed

📄 packages/analysis/src/css/linter/issues/transform.ts:148-155
When a Sass block has an incomplete range, isOutsideSassEmbeddedBlock returns !hasSassBlockWithIncompleteRange (false), so the warning is kept even if it definitively fell within a complete non-Sass block (e.g. a css/less block). This can surface a sass-only rule on plain CSS code. It's a conservative tradeoff, but you could suppress precisely by returning true when the warning matches a complete non-Sass block range, before falling back to the incomplete-range guard.

🤖 Prompt for agents
Code Review: Adds SCSS-aware css:S4662 analysis with independent targeting for plain CSS and SCSS, addressing the Sass filter and warning suppression findings. Consider ensuring the sonarRulesReady rejection wraps APIError properly.

1. 💡 Edge Case: sonarRulesReady rejection bypasses APIError wrapping
   Files: packages/analysis/src/css/linter/wrapper.ts:98-107, packages/analysis/src/css/rules/S8757/rule.ts:25-27, packages/analysis/src/css/rules/index.ts:28

   `await sonarRulesReady` at wrapper.ts:98 sits outside the `.catch` attached to `stylelint.lint(...)`, so if the module-level `ruleReady` promise (built from `stylelint.rules[UPSTREAM_RULE]`) ever rejects, `lint()` throws a raw error instead of the wrapped `APIError.linterError`, and the module-level promise can also surface as an unhandled rejection if `lint()` is never called. This is unlikely for a built-in stylelint rule, but wrapping the await (e.g. try/catch converting to APIError) would keep failure handling consistent.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqube-next

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant