@@ -5,6 +5,8 @@ import { resolveMatches } from './generateRules'
5
5
import bigSign from '../util/bigSign'
6
6
import escapeClassName from '../util/escapeClassName'
7
7
8
+ /** @typedef {Map<string, [any, import('postcss').Rule[]]> } ApplyCache */
9
+
8
10
function extractClasses ( node ) {
9
11
let classes = new Set ( )
10
12
let container = postcss . root ( { nodes : [ node . clone ( ) ] } )
@@ -35,6 +37,83 @@ function prefix(context, selector) {
35
37
return typeof prefix === 'function' ? prefix ( selector ) : prefix + selector
36
38
}
37
39
40
+ function * pathToRoot ( node ) {
41
+ yield node
42
+ while ( node . parent ) {
43
+ yield node . parent
44
+ node = node . parent
45
+ }
46
+ }
47
+
48
+ /**
49
+ * @param {import('postcss').Node } node
50
+ */
51
+ function structuralCloneOfNode ( node ) {
52
+ for ( let parent of pathToRoot ( node ) ) {
53
+ if ( node === parent ) {
54
+ continue
55
+ }
56
+
57
+ if ( parent . type === 'root' ) {
58
+ break
59
+ }
60
+
61
+ node = parent . clone ( {
62
+ nodes : [ node ] ,
63
+ } )
64
+ }
65
+
66
+ return node
67
+ }
68
+
69
+ /**
70
+ * @param {import('postcss').Root } root
71
+ */
72
+ function buildLocalApplyCache ( root , context ) {
73
+ /** @type {ApplyCache } */
74
+ let cache = new Map ( )
75
+
76
+ let reservedBits = 0n
77
+ let tmp = context . layerOrder . utilities >> 3n
78
+ while ( tmp > 1n ) {
79
+ tmp = tmp >> 1n
80
+ reservedBits ++
81
+ }
82
+
83
+ let highestOffset = 1n << reservedBits
84
+
85
+ root . walkRules ( ( rule , idx ) => {
86
+ // Ignore rules generated by Tailwind
87
+ for ( let node of pathToRoot ( rule ) ) {
88
+ if ( node . raws . tailwind ?. layer !== undefined ) {
89
+ return
90
+ }
91
+ }
92
+
93
+ // Walk to the top of the rule
94
+ let container = structuralCloneOfNode ( rule )
95
+
96
+ for ( let className of extractClasses ( rule ) ) {
97
+ let list = cache . get ( className ) || [ ]
98
+ cache . set ( className , list )
99
+
100
+ list . push ( [
101
+ {
102
+ layer : 'user' ,
103
+ sort : BigInt ( idx ) + highestOffset ,
104
+ important : false ,
105
+ } ,
106
+ container ,
107
+ ] )
108
+ }
109
+ } )
110
+
111
+ return cache
112
+ }
113
+
114
+ /**
115
+ * @returns {ApplyCache }
116
+ */
38
117
function buildApplyCache ( applyCandidates , context ) {
39
118
for ( let candidate of applyCandidates ) {
40
119
if ( context . notClassCache . has ( candidate ) || context . applyClassCache . has ( candidate ) ) {
@@ -62,6 +141,17 @@ function buildApplyCache(applyCandidates, context) {
62
141
return context . applyClassCache
63
142
}
64
143
144
+ /**
145
+ * @param {ApplyCache[] } caches
146
+ * @returns {ApplyCache }
147
+ */
148
+ function combineCaches ( caches ) {
149
+ return {
150
+ get : ( name ) => caches . flatMap ( ( cache ) => cache . get ( name ) || [ ] ) ,
151
+ has : ( name ) => caches . some ( ( cache ) => cache . has ( name ) ) ,
152
+ }
153
+ }
154
+
65
155
function extractApplyCandidates ( params ) {
66
156
let candidates = params . split ( / [ \s \t \n ] + / g)
67
157
@@ -72,7 +162,7 @@ function extractApplyCandidates(params) {
72
162
return [ candidates , false ]
73
163
}
74
164
75
- function processApply ( root , context ) {
165
+ function processApply ( root , context , localCache ) {
76
166
let applyCandidates = new Set ( )
77
167
78
168
// Collect all @apply rules and candidates
@@ -90,7 +180,7 @@ function processApply(root, context) {
90
180
// Start the @apply process if we have rules with @apply in them
91
181
if ( applies . length > 0 ) {
92
182
// Fill up some caches!
93
- let applyClassCache = buildApplyCache ( applyCandidates , context )
183
+ let applyClassCache = combineCaches ( [ localCache , buildApplyCache ( applyCandidates , context ) ] )
94
184
95
185
/**
96
186
* When we have an apply like this:
@@ -302,12 +392,14 @@ function processApply(root, context) {
302
392
}
303
393
304
394
// Do it again, in case we have other `@apply` rules
305
- processApply ( root , context )
395
+ processApply ( root , context , localCache )
306
396
}
307
397
}
308
398
309
399
export default function expandApplyAtRules ( context ) {
310
400
return ( root ) => {
311
- processApply ( root , context )
401
+ let localCache = buildLocalApplyCache ( root , context )
402
+
403
+ processApply ( root , context , localCache )
312
404
}
313
405
}
0 commit comments