1
+ var balanced = require ( 'balanced-match' ) ;
2
+
1
3
var generateScopeList = require ( './generate-scope-list' ) ;
2
4
var isNodeUnderScope = require ( './is-node-under-scope' ) ;
3
5
var gatherVariableDependencies = require ( './gather-variable-dependencies' ) ;
4
6
5
7
var findNodeAncestorWithSelector = require ( './find-node-ancestor-with-selector' ) ;
6
8
var cloneSpliceParentOntoNodeWhen = require ( './clone-splice-parent-onto-node-when' ) ;
7
9
8
-
9
-
10
- // var() = var( <custom-property-name> [, <any-value> ]? )
11
- // matches `name[, fallback]`, captures "name" and "fallback"
12
- // See: http://dev.w3.org/csswg/css-variables/#funcdef-var
13
- var RE_VAR_FUNC = ( / v a r \( \s * ( - - [ ^ , \s ] + ?) (?: \s * , \s * ( .+ ) ) ? \s * \) / ) ;
10
+ // Regexp to capture variable names
11
+ var RE_VAR_FUNC = ( / v a r \( \s * ( - - [ ^ , \s ) ] + ) / ) ;
14
12
15
13
function toString ( value ) {
16
14
return String ( value ) ;
@@ -27,26 +25,53 @@ function toString(value) {
27
25
var resolveValue = function ( decl , map , /*optional*/ ignorePseudoScope , /*internal debugging*/ _debugIsInternal ) {
28
26
var debugIndent = _debugIsInternal ? '\t' : '' ;
29
27
28
+ var matchingVarDecl = undefined ;
30
29
var resultantValue = toString ( decl . value ) ;
31
30
var warnings = [ ] ;
32
31
33
- var variablesUsedInValueMap = { } ;
34
- // Use `replace` as a loop to go over all occurrences with the `g` flag
35
- resultantValue . replace ( new RegExp ( RE_VAR_FUNC . source , 'g' ) , function ( match , variableName , fallback ) {
32
+ // Match all variables first so we can later on if there are circular dependencies
33
+ var variablesUsedInValueMap = { }
34
+ // Create a temporary variable, storing resultantValue variable value
35
+ var remainingVariableValue = resultantValue ;
36
+ // Use balanced lib to find var() declarations and store variable names
37
+ while ( ( matchingVarDecl = balanced ( 'var(' , ')' , remainingVariableValue ) ) ) {
38
+ // Split at the comma to find variable name and fallback value
39
+ // There may be other commas in the values so this isn't necessarily just 2 pieces
40
+ var variableFallbackSplitPieces = matchingVarDecl . body . split ( ',' ) ;
41
+
42
+ // Get variable name and fallback, filtering empty items
43
+ var variableName = variableFallbackSplitPieces [ 0 ] . trim ( ) ;
44
+
45
+ // add variable found in the object
36
46
variablesUsedInValueMap [ variableName ] = true ;
37
- } ) ;
47
+
48
+ // Replace variable name (first occurence only) from result, to avoid circular loop
49
+ remainingVariableValue = ( matchingVarDecl . pre || '' ) + matchingVarDecl . body . replace ( variableName , '' ) + ( matchingVarDecl . post || '' ) ;
50
+ }
51
+ // clear temporary variable
52
+ remainingVariableValue = undefined ;
53
+
38
54
var variablesUsedInValue = Object . keys ( variablesUsedInValueMap ) ;
39
55
40
56
//console.log(debugIndent, (_debugIsInternal ? '' : 'Try resolving'), generateScopeList(decl.parent, true), `ignorePseudoScope=${ignorePseudoScope}`, '------------------------');
41
57
42
58
// Resolve any var(...) substitutons
43
59
var isResultantValueUndefined = false ;
44
- resultantValue = resultantValue . replace ( new RegExp ( RE_VAR_FUNC . source , 'g' ) , function ( match , variableName , fallback ) {
45
- // Loop through the list of declarations for that value and find the one that best matches
46
- // By best match, we mean, the variable actually applies. Criteria:
47
- // - is under the same scope
48
- // - The latest defined `!important` if any
49
- var matchingVarDeclMapItem ;
60
+
61
+ // var() = var( <custom-property-name> [, <any-value> ]? )
62
+ // matches `name[, fallback]`, captures "name" and "fallback"
63
+ // See: http://dev.w3.org/csswg/css-variables/#funcdef-var
64
+ while ( ( matchingVarDecl = balanced ( 'var(' , ')' , resultantValue ) ) ) {
65
+ var matchingVarDeclMapItem = undefined ;
66
+
67
+ // Split at the comma to find variable name and fallback value
68
+ // There may be other commas in the values so this isn't necessarily just 2 pieces
69
+ var variableFallbackSplitPieces = matchingVarDecl . body . split ( ',' ) ;
70
+
71
+ // Get variable name and fallback, filtering empty items
72
+ var variableName = variableFallbackSplitPieces [ 0 ] . trim ( ) ;
73
+ var fallback = variableFallbackSplitPieces . length > 1 ? variableFallbackSplitPieces . slice ( 1 ) . join ( ',' ) . trim ( ) : undefined ;
74
+
50
75
( map [ variableName ] || [ ] ) . forEach ( function ( varDeclMapItem ) {
51
76
// Make sure the variable declaration came from the right spot
52
77
// And if the current matching variable is already important, a new one to replace it has to be important
@@ -97,10 +122,9 @@ var resolveValue = function(decl, map, /*optional*/ignorePseudoScope, /*internal
97
122
warnings . push ( [ 'variable ' + variableName + ' is undefined and used without a fallback' , { node : decl } ] ) ;
98
123
}
99
124
100
- //console.log(debugIndent, 'replaceValue', replaceValue);
101
-
102
- return replaceValue ;
103
- } ) ;
125
+ // Replace original declaration with found value
126
+ resultantValue = ( matchingVarDecl . pre || '' ) + replaceValue + ( matchingVarDecl . post || '' )
127
+ }
104
128
105
129
return {
106
130
// The resolved value
0 commit comments