[scss][less] Accept keyframe selectors in nested rule set declarations - #502
Open
Rusty Raven (kakiuwang-ui) wants to merge 1 commit into
Open
[scss][less] Accept keyframe selectors in nested rule set declarations#502Rusty Raven (kakiuwang-ui) wants to merge 1 commit into
Rusty Raven (kakiuwang-ui) wants to merge 1 commit into
Conversation
Author
|
@microsoft-github-policy-service agree |
Keyframe selectors such as `0% { ... }` are valid inside mixin bodies
(and any content that may be included into a @Keyframes rule), but the
SCSS and LESS parsers only accepted them via two per-construct special
cases (scss @include content blocks, less detached rulesets), so @mixin
declaration bodies raised false 'css-rcurlyexpected' errors — and the
same bug survived one nesting level deeper inside @if/@each/@for and in
less parametric mixins.
Fix it in the shared fallback instead: try _tryParseKeyframeSelector in
the non-at-keyword branch of the scss/less _parseRuleSetDeclaration,
after _tryParseRuleset (so plain rulesets like `e1 { }` keep their
RuleSet node type, as the selector-printing tests require) and before
_parseDeclaration (which would otherwise consume `from, 50%` and emit
a colon-expected error). This subsumes the two existing special-case
body parsers, which are removed. Plain CSS is unchanged and still
rejects keyframe selectors outside @Keyframes.
Matches dart-sass, which parses mixin bodies permissively and validates
selectors at evaluation time.
Fixes microsoft/vscode#227452
Rusty Raven (kakiuwang-ui)
force-pushed
the
fix/mixin-keyframe-selectors
branch
from
July 25, 2026 19:14
5daeb06 to
1e92353
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes microsoft/vscode#227452
Problem
The SCSS parser reports false errors (
css-rcurlyexpected,css-ruleorselectorexpected) for mixins that contain keyframe selectors, even though this is valid Sass that compiles fine:The same class of bug also reproduces one nesting level deeper (
@mixin a { @if $b { 0% { } } }), inside@includecontent blocks wrapped in control statements, and in LESS parametric mixins (.m() { 0% { } }— cf. microsoft/vscode#28091, which fixed only detached rulesets in 2017).Fix
Rather than adding another per-construct special case (there were already two:
_parseMixinReferenceBodyStatementfor scss@includebodies and_parseDetachedRuleSetBodyfor less detached rulesets, both added for vscode#28091), accept keyframe selectors in the shared nested fallback: the non-at-keyword branch of the scss/less_parseRuleSetDeclarationnow tries_tryParseKeyframeSelector:_tryParseRuleset, so plain nested rulesets likee1 { }keep theirRuleSetnode type (the existingSCSS - Selector Printing › nested selectortest guards this), and_parseDeclaration, which would otherwise consumefrom, 50%and emit a colon-expected error.Because every nested construct (
@mixinbodies,@includecontent blocks,@if/@each/@forbodies, less mixins and detached rulesets) funnels through_parseRuleSetDeclaration, this one change covers them all, and the two existing special-case body parsers are removed (net −9 lines in the parsers)._tryParseKeyframeSelectorfully backtracks, so declarations, variable declarations and error recovery are unaffected.Plain CSS is unchanged:
.a { 0% { } }in a.cssfile still errors, since the base parser's_parseRuleSetDeclarationis untouched.This matches dart-sass/less semantics, which parse rule bodies permissively and validate selectors at evaluation time (a mixin declaration cannot know its inclusion site).
Tests
Added parser tests for scss (
0%/100%in@mixin, mixedfrom, 50%lists, keyframe selectors under@if/@elseinside a mixin) and less (parametric mixins with0%/100%and mixed lists). Full suite passes: 710 pass, 0 fail.