@@ -76,50 +76,99 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
76
76
77
77
78
78
79
+
79
80
// Collect all of the variables defined
80
81
// ---------------------------------------------------------
81
82
// ---------------------------------------------------------
82
- eachCssVariableDeclaration ( css , function ( decl ) {
83
+ eachCssVariableDeclaration ( css , function ( variableDecl ) {
83
84
// We cache the parent rule because after decl removal, it will be undefined
84
- const declParentRule = decl . parent ;
85
- const variableName = decl . prop ;
85
+ const variableDeclParentRule = variableDecl . parent ;
86
+ const variableName = variableDecl . prop ;
87
+ const variableValue = variableDecl . value ;
88
+ const isImportant = variableDecl . important || false ;
89
+ const variableSelectorBranchs = generateSelectorBranchesFromPostcssNode ( variableDeclParentRule ) ;
90
+
91
+ debug ( `Collecting ${ variableName } =${ variableValue } isImportant=${ isImportant } from ${ variableDeclParentRule . selector . toString ( ) } ` ) ;
86
92
87
93
map [ variableName ] = ( map [ variableName ] || [ ] ) . concat ( {
88
94
name : variableName ,
89
- value : decl . value ,
90
- isImportant : decl . important || false ,
91
- selectorBranches : generateSelectorBranchesFromPostcssNode ( declParentRule )
95
+ value : variableValue ,
96
+ isImportant,
97
+ selectorBranches : variableSelectorBranchs
98
+ } ) ;
99
+
100
+
101
+ // Expand/rollout/unroll variable usage
102
+ // Where we define variables, also add in any usage that falls under scope
103
+ // ex.
104
+ // Before:
105
+ // .foo { --color: #f00; color: var(--color); }
106
+ // .foo:hover { --color: #0f0; };
107
+ // After:
108
+ // .foo { color: #f00; }
109
+ // .foo:hover { color: #0f0; }
110
+ // --------------------------------
111
+ css . walkDecls ( function ( usageDecl ) {
112
+ // Avoid duplicating the usage decl on itself
113
+ if ( variableDeclParentRule === usageDecl . parent ) {
114
+ return ;
115
+ }
116
+
117
+ const usageSelectorBranches = generateSelectorBranchesFromPostcssNode ( usageDecl . parent ) ;
118
+
119
+ variableSelectorBranchs . some ( ( variableSelectorBranch ) => {
120
+ return usageSelectorBranches . some ( ( usageSelectorBranch ) => {
121
+ // In this case, we look whether the usage is under the scope of the definition
122
+ const isUnderScope = isSelectorBranchUnderScope ( usageSelectorBranch , variableSelectorBranch ) ;
123
+
124
+ debug ( `Should expand usage? isUnderScope=${ isUnderScope } ` , usageSelectorBranch . selector . toString ( ) , '|' , variableSelectorBranch . selector . toString ( ) )
125
+
126
+ if ( isUnderScope ) {
127
+ usageDecl . value . replace ( new RegExp ( RE_VAR_FUNC . source , 'g' ) , ( match , matchedVariableName ) => {
128
+ if ( matchedVariableName === variableName ) {
129
+ variableDecl . after ( usageDecl . clone ( ) ) ;
130
+ }
131
+ } ) ;
132
+ }
133
+
134
+ return isUnderScope ;
135
+ } ) ;
136
+ } ) ;
92
137
} ) ;
93
138
139
+
140
+
94
141
// Remove the variable declaration because they are pretty much useless after we resolve them
95
142
if ( ! opts . preserve ) {
96
- decl . remove ( ) ;
143
+ variableDecl . remove ( ) ;
97
144
}
98
145
// Or we can also just show the computed value used for that variable
99
146
else if ( opts . preserve === 'computed' ) {
100
147
// TODO: put computed value here
101
148
}
102
149
103
150
// Clean up the rule that declared them if it doesn't have anything left after we potentially remove the variable decl
104
- if ( declParentRule . nodes . length <= 0 ) {
105
- declParentRule . remove ( ) ;
151
+ if ( variableDeclParentRule . nodes . length <= 0 ) {
152
+ variableDeclParentRule . remove ( ) ;
106
153
}
107
154
} ) ;
108
155
109
156
debug ( 'map' , map ) ;
110
157
158
+ debug ( 'After collecting variables ------' ) ;
159
+ debug ( css . toString ( ) ) ;
160
+ debug ( '---------------------------------' ) ;
111
161
112
162
113
163
// Resolve variables everywhere
114
164
// ---------------------------------------------------------
115
165
// ---------------------------------------------------------
116
166
css . walkDecls ( function ( decl ) {
117
- // If it uses variables
118
- // and is not a variable declarations that we may be preserving from earlier
167
+ // Avoid any variable decls, `--foo: var(--bar);`, that may have been preserved
119
168
if ( ! RE_VAR_PROP . test ( decl . prop ) ) {
120
169
const selectorBranches = generateSelectorBranchesFromPostcssNode ( decl . parent ) ;
121
170
122
- decl . value = decl . value . replace ( new RegExp ( RE_VAR_FUNC . source , 'g' ) , ( match , variableName ) => {
171
+ decl . value = decl . value . replace ( new RegExp ( RE_VAR_FUNC . source , 'g' ) , ( match , variableName , fallback ) => {
123
172
debug ( 'usage' , variableName ) ;
124
173
const variableEntries = map [ variableName ] || [ ] ;
125
174
@@ -131,10 +180,11 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
131
180
// We only need to find one branch that matches
132
181
variableEntry . selectorBranches . some ( ( variableSelectorBranch ) => {
133
182
return selectorBranches . some ( ( selectorBranch ) => {
183
+ // Look whether the variable definition is under the scope of the usage
134
184
const isUnderScope = isSelectorBranchUnderScope ( variableSelectorBranch , selectorBranch ) ;
135
185
const specificity = getSpecificity ( variableSelectorBranch . selector . toString ( ) ) ;
136
186
137
- debug ( `isUnderScope=${ isUnderScope } compareSpecificity=${ compareSpecificity ( specificity , currentGreatestSpecificity ) } specificity=${ specificity } ` , variableSelectorBranch . selector . toString ( ) , selectorBranch . selector . toString ( ) )
187
+ debug ( `isUnderScope=${ isUnderScope } compareSpecificity=${ compareSpecificity ( specificity , currentGreatestSpecificity ) } specificity=${ specificity } ` , variableSelectorBranch . selector . toString ( ) , '|' , selectorBranch . selector . toString ( ) )
138
188
139
189
if ( isUnderScope && compareSpecificity ( specificity , currentGreatestSpecificity ) >= 0 ) {
140
190
currentGreatestSpecificity = specificity ;
@@ -148,7 +198,13 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
148
198
149
199
debug ( 'currentGreatestVariableEntry' , currentGreatestVariableEntry ) ;
150
200
151
- return currentGreatestVariableEntry . value ;
201
+ const resultantValue = ( currentGreatestVariableEntry && currentGreatestVariableEntry . value ) || fallback ;
202
+
203
+ if ( ! resultantValue ) {
204
+ result . warn ( [ 'variable ' + variableName + ' is undefined and used without a fallback' , { node : decl } ] ) ;
205
+ }
206
+
207
+ return resultantValue || 'undefined' ;
152
208
} ) ;
153
209
}
154
210
} ) ;
0 commit comments