@@ -6,7 +6,7 @@ export function getVariantsFromClassName(
6
6
className : string
7
7
) : { variants : string [ ] ; offset : number } {
8
8
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 )
10
10
let variants = new Set < string > ( )
11
11
let offset = 0
12
12
@@ -29,66 +29,34 @@ export function getVariantsFromClassName(
29
29
return { variants : Array . from ( variants ) , offset }
30
30
}
31
31
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
34
37
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 ]
50
40
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
68
45
}
69
-
70
- separatorIndex ++
71
46
}
72
47
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 ( )
83
56
}
84
57
}
85
58
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
94
62
}
0 commit comments