@@ -11,12 +11,13 @@ const CSSVariablesCollectorPlugin = module.exports = function(config) {
11
11
this . ruleStack = [ ] ;
12
12
this . mixinStack = [ ] ;
13
13
this . parenStack = [ ] ;
14
- this . importStack = [ ] ;
15
14
} ;
16
15
17
16
CSSVariablesCollectorPlugin . prototype = {
18
17
18
+ // needed to keep the less variable references intact to use this info for the CSS variables references
19
19
isPreEvalVisitor : true ,
20
+
20
21
isReplacing : true ,
21
22
22
23
_isInMixinOrParen ( ) {
@@ -27,28 +28,41 @@ CSSVariablesCollectorPlugin.prototype = {
27
28
return this . ruleStack . length > 0 && ! this . ruleStack [ this . ruleStack . length - 1 ] . variable ;
28
29
} ,
29
30
30
- _isVarInLibrary ( ) {
31
- // the last less file defines the location of the css variable and this must
32
- // be in the path of the current library, otherwise it is an external variable
33
- const regexp = new RegExp ( `^/resources/${ this . config . libPath } /themes/` ) ;
34
- return this . importStack . length > 0 ? regexp . test ( this . importStack [ this . importStack . length - 1 ] . importedFilename ) : true ;
31
+ _isVarInLibrary ( { varName, filename} ) {
32
+ // for libraries we check that the file is within the libraries theme path
33
+ // in all other cases with no filename (indicates calculated variables)
34
+ // or in case of variables in standalone less files we just include them!
35
+ const include = ! filename ||
36
+ ( this . config . libPath ? filename . startsWith ( `/resources/${ this . config . libPath } /themes/` ) : true ) ;
37
+ return include ;
35
38
} ,
36
39
37
40
_isRelevant ( ) {
38
41
return ! this . _isInMixinOrParen ( ) && this . _isVarInRule ( ) ;
39
42
} ,
40
43
41
- toLessVariables ( ) {
44
+ toLessVariables ( varsOverride ) {
45
+ const vars = { } ;
46
+ Object . keys ( this . vars ) . forEach ( ( key ) => {
47
+ const override = this . vars [ key ] . updateAfterEval && varsOverride [ key ] !== undefined ;
48
+ if ( override ) {
49
+ console . log ( `Override variable "${ key } " from "${ this . vars [ key ] . css } " to "${ varsOverride [ key ] . css } "` ) ;
50
+ }
51
+ vars [ key ] = {
52
+ css : override ? varsOverride [ key ] . css : this . vars [ key ] . css ,
53
+ export : this . vars [ key ] . export
54
+ } ;
55
+ } ) ;
42
56
let lessVariables = "" ;
43
- Object . keys ( this . vars ) . forEach ( ( value , index ) => {
44
- lessVariables += "@" + value + ": " + this . vars [ value ] . css + ";\n" ;
57
+ Object . keys ( vars ) . forEach ( ( value , index ) => {
58
+ lessVariables += "@" + value + ": " + vars [ value ] . css + ";\n" ;
45
59
} ) ;
46
60
Object . keys ( this . calcVars ) . forEach ( ( value , index ) => {
47
61
lessVariables += "@" + value + ": " + this . calcVars [ value ] . css + ";\n" ;
48
62
} ) ;
49
63
lessVariables += "\n:root {\n" ;
50
- Object . keys ( this . vars ) . forEach ( ( value , index ) => {
51
- if ( this . vars [ value ] . export ) {
64
+ Object . keys ( vars ) . forEach ( ( value , index ) => {
65
+ if ( vars [ value ] . export ) {
52
66
lessVariables += "--" + value + ": @" + value + ";\n" ;
53
67
}
54
68
} ) ;
@@ -96,7 +110,7 @@ CSSVariablesCollectorPlugin.prototype = {
96
110
} ,
97
111
98
112
visitCall ( node , visitArgs ) {
99
- // if variables are used inside rules, generate a new dynamic variable for it!
113
+ // if variables are used inside rules, generate a new calculated variable for it!
100
114
const isRelevantFunction = typeof less . tree . functions [ node . name ] === "function" && [ "rgba" ] . indexOf ( node . name ) === - 1 ;
101
115
if ( this . _isRelevant ( ) && isRelevantFunction ) {
102
116
const css = this . _getCSS ( node ) ;
@@ -110,7 +124,9 @@ CSSVariablesCollectorPlugin.prototype = {
110
124
}
111
125
this . calcVars [ newName ] = {
112
126
css : css ,
113
- export : this . _isVarInLibrary ( )
127
+ export : this . _isVarInLibrary ( {
128
+ varName : newName
129
+ } )
114
130
} ;
115
131
return new less . tree . Call ( "var" , [ new less . tree . Anonymous ( "--" + newName , node . index , node . currentFileInfo , node . mapLines ) ] ) ;
116
132
}
@@ -169,30 +185,32 @@ CSSVariablesCollectorPlugin.prototype = {
169
185
return node ;
170
186
} ,
171
187
172
- visitImport ( node , visitArgs ) {
173
- // store the import context
174
- this . importStack . push ( node ) ;
175
- return node ;
176
- } ,
177
-
178
- visitImportOut ( node ) {
179
- // remove import context
180
- this . importStack . pop ( ) ;
181
- return node ;
182
- } ,
183
-
184
188
visitRuleset ( node , visitArgs ) {
185
189
node . rules . forEach ( ( value ) => {
186
190
const isVarDeclaration = value instanceof less . tree . Rule && typeof value . name === "string" && value . name . startsWith ( "@" ) ;
187
191
if ( ! this . _isInMixinOrParen ( ) && isVarDeclaration ) {
188
192
// add the variable declaration to the list of vars
189
- this . vars [ value . name . substr ( 1 ) ] = {
193
+ const varName = value . name . substr ( 1 ) ;
194
+ this . vars [ varName ] = {
190
195
css : this . _getCSS ( value . value ) ,
191
- export : this . _isVarInLibrary ( )
196
+ export : this . _isVarInLibrary ( {
197
+ varName,
198
+ filename : value . currentFileInfo . filename
199
+ } )
192
200
} ;
193
201
}
194
202
} ) ;
195
203
return node ;
204
+ } ,
205
+
206
+ visitUrl ( node , visitArgs ) {
207
+ // we mark the less variables which should be updated after eval
208
+ // => strangewise less variables with "none" values are also urls
209
+ // after the less variables have been evaluated
210
+ if ( this . ruleStack . length > 0 && this . ruleStack [ 0 ] . variable ) {
211
+ this . vars [ this . ruleStack [ 0 ] . name . substr ( 1 ) ] . updateAfterEval = true ;
212
+ }
213
+ return node ;
196
214
}
197
215
198
216
} ;
0 commit comments