Skip to content

Commit

Permalink
Fix buggy selector transformation
Browse files Browse the repository at this point in the history
  • Loading branch information
askoufis committed Nov 20, 2024
1 parent 7047243 commit 4329b36
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/flat-humans-hammer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@vanilla-extract/css': patch
---

Fixes a bug that caused invalid selectors to be generated when adjacent classnames contained a substring equal to another local classname
55 changes: 55 additions & 0 deletions packages/css/src/transformCss.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2299,6 +2299,61 @@ describe('transformCss', () => {
}
`);
});

it('should handle adjacent classnames containing a separate local classname as a substring', () => {
// Note that `classname2` starts and ends with the same character, so when two `classname1`s are
// adjacent, the resulting string will contain `classname2` as a substring
const classname1 = 'debugName_hash1';
const classname2 = 'debugName_hash1d';

expect(
transformCss({
composedClassLists: [],
localClassNames: [classname1, classname2],

cssObjs: [
{
type: 'local',
selector: classname1,
rule: {
selectors: {
['&&']: {
background: 'black',
},
[`${classname2}&`]: {
background: 'orange',
},
[`&${classname2}&`]: {
background: 'orange',
},
[`${classname2}${classname2}&`]: {
background: 'orange',
},
},
},
},
{
type: 'local',
selector: classname2,
rule: {},
},
],
}).join('\n'),
).toMatchInlineSnapshot(`
.debugName_hash1.debugName_hash1 {
background: black;
}
.debugName_hash1d.debugName_hash1 {
background: orange;
}
.debugName_hash1.debugName_hash1d.debugName_hash1 {
background: orange;
}
.debugName_hash1d.debugName_hash1d.debugName_hash1 {
background: orange;
}
`);
});
});

endFileScope();
19 changes: 14 additions & 5 deletions packages/css/src/transformCss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,11 +317,20 @@ class Stylesheet {
const [endIndex, [firstMatch]] = results[i];
const startIndex = endIndex - firstMatch.length + 1;

if (startIndex >= lastReplaceIndex) {
// Class names can be substrings of other class names
// e.g. '_1g1ptzo1' and '_1g1ptzo10'
// If the startIndex >= lastReplaceIndex, then
// this is the case and this replace should be skipped
// Class names can be substrings of other class names
// e.g. '_1g1ptzo1' and '_1g1ptzo10'
//
// Additionally, concatenated classnames can contain substrings equal to other classnames
// e.g. '&&' where '&' is 'debugName_hash1' and 'debugName_hash1d' is also a local classname
// Before transforming the selector, this would look like `debugName_hash1debugName_hash1`
// which contains the substring `debugName_hash1d`’.
//
// In either of these cases, the last replace index will occur either before or within the
// current replacement range (from `startIndex` to `endIndex`).
// If this occurs, we skip the replacement to avoid transforming the selector incorrectly.
const skipReplacement = lastReplaceIndex <= endIndex;

if (skipReplacement) {
continue;
}

Expand Down

0 comments on commit 4329b36

Please sign in to comment.