File tree Expand file tree Collapse file tree 3 files changed +74
-5
lines changed Expand file tree Collapse file tree 3 files changed +74
-5
lines changed Original file line number Diff line number Diff line change 1+ ---
2+ ' @vanilla-extract/css ' : patch
3+ ---
4+
5+ Fixes a bug that caused invalid selectors to be generated when adjacent classnames contained a substring equal to another local classname
Original file line number Diff line number Diff line change @@ -2299,6 +2299,61 @@ describe('transformCss', () => {
22992299 }
23002300 ` ) ;
23012301 } ) ;
2302+
2303+ it ( 'should handle adjacent classnames containing a separate local classname as a substring' , ( ) => {
2304+ // Note that `classname2` starts and ends with the same character, so when two `classname1`s are
2305+ // adjacent, the resulting string will contain `classname2` as a substring
2306+ const classname1 = 'debugName_hash1' ;
2307+ const classname2 = 'debugName_hash1d' ;
2308+
2309+ expect (
2310+ transformCss ( {
2311+ composedClassLists : [ ] ,
2312+ localClassNames : [ classname1 , classname2 ] ,
2313+
2314+ cssObjs : [
2315+ {
2316+ type : 'local' ,
2317+ selector : classname1 ,
2318+ rule : {
2319+ selectors : {
2320+ [ '&&' ] : {
2321+ background : 'black' ,
2322+ } ,
2323+ [ `${ classname2 } &` ] : {
2324+ background : 'orange' ,
2325+ } ,
2326+ [ `&${ classname2 } &` ] : {
2327+ background : 'orange' ,
2328+ } ,
2329+ [ `${ classname2 } ${ classname2 } &` ] : {
2330+ background : 'orange' ,
2331+ } ,
2332+ } ,
2333+ } ,
2334+ } ,
2335+ {
2336+ type : 'local' ,
2337+ selector : classname2 ,
2338+ rule : { } ,
2339+ } ,
2340+ ] ,
2341+ } ) . join ( '\n' ) ,
2342+ ) . toMatchInlineSnapshot ( `
2343+ .debugName_hash1.debugName_hash1 {
2344+ background: black;
2345+ }
2346+ .debugName_hash1d.debugName_hash1 {
2347+ background: orange;
2348+ }
2349+ .debugName_hash1.debugName_hash1d.debugName_hash1 {
2350+ background: orange;
2351+ }
2352+ .debugName_hash1d.debugName_hash1d.debugName_hash1 {
2353+ background: orange;
2354+ }
2355+ ` ) ;
2356+ } ) ;
23022357} ) ;
23032358
23042359endFileScope ( ) ;
Original file line number Diff line number Diff line change @@ -317,11 +317,20 @@ class Stylesheet {
317317 const [ endIndex , [ firstMatch ] ] = results [ i ] ;
318318 const startIndex = endIndex - firstMatch . length + 1 ;
319319
320- if ( startIndex >= lastReplaceIndex ) {
321- // Class names can be substrings of other class names
322- // e.g. '_1g1ptzo1' and '_1g1ptzo10'
323- // If the startIndex >= lastReplaceIndex, then
324- // this is the case and this replace should be skipped
320+ // Class names can be substrings of other class names
321+ // e.g. '_1g1ptzo1' and '_1g1ptzo10'
322+ //
323+ // Additionally, concatenated classnames can contain substrings equal to other classnames
324+ // e.g. '&&' where '&' is 'debugName_hash1' and 'debugName_hash1d' is also a local classname
325+ // Before transforming the selector, this would look like `debugName_hash1debugName_hash1`
326+ // which contains the substring `debugName_hash1d`’.
327+ //
328+ // In either of these cases, the last replace index will occur either before or within the
329+ // current replacement range (from `startIndex` to `endIndex`).
330+ // If this occurs, we skip the replacement to avoid transforming the selector incorrectly.
331+ const skipReplacement = lastReplaceIndex <= endIndex ;
332+
333+ if ( skipReplacement ) {
325334 continue ;
326335 }
327336
You can’t perform that action at this time.
0 commit comments