Skip to content

fix: parse @{var} interpolation in at-rule prelude (#180) - #181

Open
dshovchko wants to merge 1 commit into
shellscape:masterfrom
dshovchko:fix/at-rule-prelude-interpolation
Open

fix: parse @{var} interpolation in at-rule prelude (#180)#181
dshovchko wants to merge 1 commit into
shellscape:masterfrom
dshovchko:fix/at-rule-prelude-interpolation

Conversation

@dshovchko

Copy link
Copy Markdown

Which issue # Fixes #180

Please check one:

  • New tests created for this change
  • Tests updated for this change

This PR:

  • Adds new API
  • Extends existing API, backwards-compatible
  • Introduces a breaking change
  • Fixes a bug

@media @{mq-xs} { … } throws CssSyntaxError: Unknown word.

PostCSS's Parser#atrule only tracks ( and [ in its brackets stack, so on the interpolation's { it takes brackets.length === 0open = true; break. The prelude is cut short and mq-xs ends up parsed as an unknown word inside the block. LessParser#atrule calls interpolation() only on the at-rule's first token, which returns false for @media (length > 1), so interpolations in the prelude were never merged.

LessParser#rule already works around the same problem for selectors — this adds the missing at-rule counterpart: @{…} token sequences in the prelude are merged into single word tokens before delegating to super.atrule().

This matters now because Less >= 4.7 deprecates the bare @media @var form and points users at exactly the syntax that could not be parsed, so codebases migrating off the deprecation become un-lintable by stylelint.

Tests

6 new parser cases in test/parser/interpolation.test.js (basic @media @{mq-xs}, no space before {, followed by a media feature, multiple interpolations, interpolation inside a feature value, plus a regression guard for the bare @media @mq-xs) and a stringify round-trip in test/stringify.test.js.
Full suite: 155 passing, lint clean.

Verification

Checked manually for regressions on @import, @plugin, variable declarations, mixin calls, detached rulesets, @supports, @media with variables inside features, and @@var indirection — all still parse and round-trip. Also ran the patched parser over a real codebase (~900 .less files, ~1800 occurrences of the syntax): everything parses and round-trips cleanly.

PostCSS's `Parser#atrule` only tracks `(` and `[` in its brackets stack, so
the `{` of an interpolation such as `@media @{mq-xs}` was treated as the
start of the at-rule block, cutting the prelude short and throwing
`Unknown word`.

Merge `@{...}` token sequences in the prelude into single word tokens
before delegating to `super.atrule()`, mirroring the workaround `rule()`
already applies to selectors.
@dshovchko

Copy link
Copy Markdown
Author

Heads up on the red ci/circleci: analysis check: the Run Linting step passes, the failure comes from the next step, npm audit --audit-level=high.

It's pre-existing and unrelated to this PR - master reports the same 46 vulnerabilities (4 low, 14 moderate, 26 high, 2 critical), all from stale devDependencies. This PR touches neither package.json nor package-lock.json, so the delta is zero.

Locally on this branch: npx ava → 155 passing, npx eslint lib test → clean.
Happy to rebase or adjust anything.

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.

Interpolation @{var} in an at-rule prelude fails to parse (@media @{mq-xs})

1 participant