fix(attributes): [attr~=""] with an empty value matches nothing#1810
fix(attributes): [attr~=""] with an empty value matches nothing#1810ursm wants to merge 1 commit into
[attr~=""] with an empty value matches nothing#1810Conversation
The `~=` handler only short-circuited to `falseFunc` for values containing whitespace. An empty value fell through to a regex `(?:^|\s)(?:$|\s)` that wrongly matched an empty attribute such as `class=""`. Per Selectors §6.3.2 an empty (or whitespace-containing) `~=` value can never be a single token and matches nothing — consistent with the empty-value short-circuit `^=`/`$=`/`*=` already have, and with browser behaviour (`[class~=""]` selects nothing in Chrome). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughThe PR extends the ChangesEmpty Attribute Value Handling
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~5 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/attributes.ts`:
- Around line 94-98: Add a runtime DOM test verifying that the selector
[foo~=''] yields no matches: in the "no matches" describe block (after the
existing compilation test using CSSselect._compileUnsafe and boolbase.falseFunc)
add a test that calls CSSselect.selectAll("[data-foo~='']", dom) and expects an
empty result (length 0) to confirm end-to-end behavior; reference the existing
dom fixture and use the same test structure as the case-insensitive tests for
consistency.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: b5d6c01f-d141-43b0-b163-e1396dac5132
📒 Files selected for processing (2)
src/attributes.tstest/attributes.ts
| it("should for ~= with an empty value", () => { | ||
| expect(CSSselect._compileUnsafe("[foo~='']")).toBe( | ||
| boolbase.falseFunc, | ||
| ); | ||
| }); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Consider adding a runtime DOM matching test for completeness.
The compilation test correctly verifies that [foo~=''] returns boolbase.falseFunc. However, consider adding a runtime test that verifies the selector returns no matches against actual DOM elements, similar to the case-insensitive tests in lines 78-84.
🧪 Suggested additional runtime test
Add this test case in the "no matches" describe block after line 98:
it("should not match elements for ~= with an empty value", () => {
const matches = CSSselect.selectAll("[data-foo~='']", dom);
expect(matches).toHaveLength(0);
});This provides end-to-end verification that the selector behavior matches expectations against actual DOM.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@test/attributes.ts` around lines 94 - 98, Add a runtime DOM test verifying
that the selector [foo~=''] yields no matches: in the "no matches" describe
block (after the existing compilation test using CSSselect._compileUnsafe and
boolbase.falseFunc) add a test that calls CSSselect.selectAll("[data-foo~='']",
dom) and expects an empty result (length 0) to confirm end-to-end behavior;
reference the existing dom fixture and use the same test structure as the
case-insensitive tests for consistency.
Problem
The
~=(whitespace-separated "one of") attribute handler only short-circuits toboolbase.falseFuncwhen the value contains whitespace. An empty value falls through to the regex(?:^|\s)(?:$|\s), which matches an empty attribute — so[class~=""]wrongly selects elements withclass="".Expected behaviour
Per Selectors §6.3.2, an empty (or whitespace-containing)
~=value can never be a single token, so it represents nothing. Browsers agree —document.querySelectorAll('[class~=""]')returns nothing in Chrome.This also makes
~=consistent with^=/$=/*=(start/end/any), which already short-circuit empty values tofalseFunc.Change
Add
value === ""to the existing short-circuit in theelement(~=) handler, plus a test mirroring the existing empty-value tests for$=/*=.🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Tests