@@ -6,7 +6,7 @@ export function getVariantsFromClassName(
66 className : string
77) : { variants : string [ ] ; offset : number } {
88 let allVariants = Object . keys ( state . variants )
9- let parts = Array . from ( splitAtTopLevelOnly ( className , state . separator ) ) . filter ( Boolean )
9+ let parts = splitAtTopLevelOnly ( className , state . separator ) . filter ( Boolean )
1010 let variants = new Set < string > ( )
1111 let offset = 0
1212
@@ -29,66 +29,34 @@ export function getVariantsFromClassName(
2929 return { variants : Array . from ( variants ) , offset }
3030}
3131
32- const REGEX_SPECIAL = / [ \\ ^ $ . * + ? ( ) [ \] { } | ] / g
33- const REGEX_HAS_SPECIAL = RegExp ( REGEX_SPECIAL . source )
32+ // https://github.com/tailwindlabs/tailwindcss/blob/a8a2e2a7191fbd4bee044523aecbade5823a8664/src/util/splitAtTopLevelOnly.js
33+ function splitAtTopLevelOnly ( input : string , separator : string ) : string [ ] {
34+ let stack : string [ ] = [ ]
35+ let parts : string [ ] = [ ]
36+ let lastPos = 0
3437
35- function regexEscape ( string : string ) : string {
36- return string && REGEX_HAS_SPECIAL . test ( string )
37- ? string . replace ( REGEX_SPECIAL , '\\$&' )
38- : string || ''
39- }
40-
41- function * splitAtTopLevelOnly ( input : string , separator : string ) : Generator < string > {
42- let SPECIALS = new RegExp ( `[(){}\\[\\]${ regexEscape ( separator ) } ]` , 'g' )
43-
44- let depth = 0
45- let lastIndex = 0
46- let found = false
47- let separatorIndex = 0
48- let separatorStart = 0
49- let separatorLength = separator . length
38+ for ( let idx = 0 ; idx < input . length ; idx ++ ) {
39+ let char = input [ idx ]
5040
51- // Find all paren-like things & character
52- // And only split on commas if they're top-level
53- for ( let match of input . matchAll ( SPECIALS ) ) {
54- let matchesSeparator = match [ 0 ] === separator [ separatorIndex ]
55- let atEndOfSeparator = separatorIndex === separatorLength - 1
56- let matchesFullSeparator = matchesSeparator && atEndOfSeparator
57-
58- if ( match [ 0 ] === '(' ) depth ++
59- if ( match [ 0 ] === ')' ) depth --
60- if ( match [ 0 ] === '[' ) depth ++
61- if ( match [ 0 ] === ']' ) depth --
62- if ( match [ 0 ] === '{' ) depth ++
63- if ( match [ 0 ] === '}' ) depth --
64-
65- if ( matchesSeparator && depth === 0 ) {
66- if ( separatorStart === 0 ) {
67- separatorStart = match . index
41+ if ( stack . length === 0 && char === separator [ 0 ] ) {
42+ if ( separator . length === 1 || input . slice ( idx , idx + separator . length ) === separator ) {
43+ parts . push ( input . slice ( lastPos , idx ) )
44+ lastPos = idx + separator . length
6845 }
69-
70- separatorIndex ++
7146 }
7247
73- if ( matchesFullSeparator && depth === 0 ) {
74- found = true
75-
76- yield input . substring ( lastIndex , separatorStart )
77- lastIndex = separatorStart + separatorLength
78- }
79-
80- if ( separatorIndex === separatorLength ) {
81- separatorIndex = 0
82- separatorStart = 0
48+ if ( char === '(' || char === '[' || char === '{' ) {
49+ stack . push ( char )
50+ } else if (
51+ ( char === ')' && stack [ stack . length - 1 ] === '(' ) ||
52+ ( char === ']' && stack [ stack . length - 1 ] === '[' ) ||
53+ ( char === '}' && stack [ stack . length - 1 ] === '{' )
54+ ) {
55+ stack . pop ( )
8356 }
8457 }
8558
86- // Provide the last segment of the string if available
87- // Otherwise the whole string since no `char`s were found
88- // This mirrors the behavior of string.split()
89- if ( found ) {
90- yield input . substring ( lastIndex )
91- } else {
92- yield input
93- }
59+ parts . push ( input . slice ( lastPos ) )
60+
61+ return parts
9462}
0 commit comments