fix(parser): improve support for scss files - #44
Merged
Merged
Conversation
`scan_value_end` previously treated any `}` at paren depth 0 as a value
terminator, so `--color: #{$brand};` was cut to `#{$brand` and the
following `}` of the interpolation was mistaken for the rule's closing
brace, throwing brace tracking off.
Track `#{ … }` as a balanced group alongside parens, and gate the `;`,
comment, and missing-semicolon-recovery branches on `interp_depth <= 0`
so SCSS interpolations parse cleanly inside any value.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Verify that the universal at-rule descent (@mixin, @if/@else, @each, @function) correctly collects definitions and var() references from SCSS-only at-rule bodies, and that statement-form @return inside a @function body doesn't pollute the property list. @each uses #{$name} interpolation and depends on the preceding scan_value_end interpolation-depth tracking. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`scan_value_end` gated the `/* … */` skip on `interp_depth <= 0`, so a
block comment inside `#{ … }` was advanced byte-by-byte. A `}` inside
the comment then matched the interpolation-close arm, popping
interp_depth one step early — the real interpolation closer was treated
as the rule's `}` and trailing properties were silently dropped.
Add a dedicated `b'/' if peek == b'*' && interp_depth > 0` arm that
consumes the comment wholesale, leaving interp tracking intact.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The parser previously advanced through `//` byte-by-byte, so a `;` or `}` inside a SCSS line comment terminated the surrounding value or popped brace_depth, silently dropping later definitions. Add `Scanner::skip_line_comment` and call it in the four scan contexts: the main loop, at-rule prelude, `@property` body walker, and `scan_value_end`. In `scan_value_end` outside parens/interp the comment terminates the value (mirroring `/* … */`); inside interpolation it is skipped so a `}` in the comment doesn't pop interp_depth; inside parens the bytes are kept verbatim so protocol-relative URLs like `url(//cdn.example.com/x.png)` parse unchanged. The at-rule prelude tracks paren_depth for the same reason — `@import url(//cdn.example.com/x.css);` must still work. cvk-ignore is intentionally not honored on `//` comments; pairing it with line comments is a separate enhancement. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous commit always treated `//` as a line comment, which silently truncates valid CSS like `--link: https://example.com/path` because the custom-property value is allowed to hold raw URLs. Branch the behavior on file extension instead: the parser now tracks a `scss` flag derived from the file path and only honors `//` line comments when the source is `.scss`. `#{ … }` interpolation tracking and the universal at-rule body descent are unaffected — neither construct is meaningful in CSS, so applying them everywhere is harmless and keeps the implementation simple. Add `test_parse_scss` for SCSS-mode tests, switch the `scss_line_comment_*` and `scss_protocol_relative_url_*` tests onto it, and pin the CSS-mode behavior with two regressions: `--link: https://…` keeps its full value and a literal `//` in a value stays as bytes. Drop the long-unused `initial_brace_depth` parameter on `parse_impl` — both call sites passed `0` and dropping it keeps the signature within clippy's argument-count limit after adding `scss`. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous SCSS line-comment arm just skipped to EOL. Authors writing `.scss` had no way to use `//` for `cvk-ignore` directives, even though that is the natural comment style in SCSS sources. Add `Scanner::scan_line_comment` that mirrors `scan_comment` (returns the trimmed body) and upgrade the main loop's SCSS-only `//` arm to run the same chain-tracking shape the block-comment arm uses: track `comment_start_line` for blank-line breaks, scan content, update `last_comment_end_line`, and push to `pending_ignores` when the body starts with `cvk-ignore`. The other three line-comment sites (`skip_at_rule_prelude`, `scan_at_property_rule`, `scan_value_end`) keep using `skip_line_comment` — they sit in positions where the directive would be meaningless, matching how `/* … */` is treated. The CSS gate is preserved: in `.css` files the arm never fires and `// cvk-ignore` produces no suppression — pinned by a regression test. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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.
Summary
Parser-level SCSS support so cvk can lint
.scssfiles without dropping definitions or corrupting brace tracking on constructs absent from plain CSS.#{ … }interpolation tracking —--color: #{$brand};no longer truncates at the inner}. Block comments inside#{ … }are skipped wholesale so a}in the comment doesn't pop interp_depth.//line comments in all four scan contexts (main loop, at-rule prelude,@propertybody, value scan). A;or}inside// …no longer terminates a value or rule. The main loop also capturescvk-ignoredirectives written as// cvk-ignore[: rule-name]. The at-rule prelude tracksparen_depthso@import url(//cdn.example.com/x.css);still works.CSS vs SCSS gating
//would silently truncate valid CSS like--link: https://example.com/path(custom-property values may hold raw URLs), so the parser carries ascssflag derived from the file extension and only honors//when the source is.scss.#{ … }tracking is on for both modes — it's harmless on CSS and keeps the implementation simple.Test plan
cargo test -p css-var-kit(full suite green; SCSS tests use a newtest_parse_scsshelper)cargo clippy -p css-var-kit --all-targets -- -D warnings--link: https://…keeps its full value; literal//in a value stays as bytes;// cvk-ignoredoes not suppress in.css.