@@ -10,8 +10,7 @@ var cloneSpliceParentOntoNodeWhen = require('./clone-splice-parent-onto-node-whe
10
10
// var() = var( <custom-property-name> [, <any-value> ]? )
11
11
// matches `name[, fallback]`, captures "name" and "fallback"
12
12
// See: http://dev.w3.org/csswg/css-variables/#funcdef-var
13
- //var RE_VAR_FUNC = (/var\(\s*(--[^,\s]+?)(?:\s*,\s*(.+))?\s*\)/);
14
- var RE_VAR_FUNC = ( / v a r \( \s * ( - - [ ^ , \s ] + ?) (?: \s * , \s * ( [ ^ ) ] + ) ) ? \s * \) / ) ;
13
+ var RE_VAR_FUNC = ( / v a r \( \s * ( - - [ ^ , \s ] + ?) (?: \s * , \s * ( [ ^ ( ) ] + | .+ ) ) ? \s * \) / ) ;
15
14
16
15
function toString ( value ) {
17
16
return String ( value ) ;
@@ -42,66 +41,69 @@ var resolveValue = function(decl, map, /*optional*/ignorePseudoScope, /*internal
42
41
43
42
// Resolve any var(...) substitutons
44
43
var isResultantValueUndefined = false ;
45
- resultantValue = resultantValue . replace ( new RegExp ( RE_VAR_FUNC . source , 'g' ) , function ( match , variableName , fallback ) {
46
- // Loop through the list of declarations for that value and find the one that best matches
47
- // By best match, we mean, the variable actually applies. Criteria:
48
- // - is under the same scope
49
- // - The latest defined `!important` if any
50
- var matchingVarDeclMapItem ;
51
- ( map [ variableName ] || [ ] ) . forEach ( function ( varDeclMapItem ) {
52
- // Make sure the variable declaration came from the right spot
53
- // And if the current matching variable is already important, a new one to replace it has to be important
54
- var isRoot = varDeclMapItem . parent . type === 'root' || varDeclMapItem . parent . selectors [ 0 ] === ':root' ;
55
44
56
- var underScope = isNodeUnderScope ( decl . parent , varDeclMapItem . parent ) ;
57
- var underScsopeIgnorePseudo = isNodeUnderScope ( decl . parent , varDeclMapItem . parent , ignorePseudoScope ) ;
58
-
59
- //console.log(debugIndent, 'isNodeUnderScope', underScope, underScsopeIgnorePseudo, generateScopeList(varDeclMapItem.parent, true), varDeclMapItem.decl.value);
60
-
61
- if (
62
- underScsopeIgnorePseudo &&
63
- // And if the currently matched declaration is `!important`, it will take another `!important` to override it
64
- ( ! ( matchingVarDeclMapItem || { } ) . isImportant || varDeclMapItem . isImportant )
65
- ) {
66
- matchingVarDeclMapItem = varDeclMapItem ;
45
+ while ( resultantValue . match ( new RegExp ( RE_VAR_FUNC . source , 'g' ) ) ) {
46
+ resultantValue = resultantValue . replace ( new RegExp ( RE_VAR_FUNC . source , 'g' ) , function ( match , variableName , fallback ) {
47
+ // Loop through the list of declarations for that value and find the one that best matches
48
+ // By best match, we mean, the variable actually applies. Criteria:
49
+ // - is under the same scope
50
+ // - The latest defined `!important` if any
51
+ var matchingVarDeclMapItem ;
52
+ ( map [ variableName ] || [ ] ) . forEach ( function ( varDeclMapItem ) {
53
+ // Make sure the variable declaration came from the right spot
54
+ // And if the current matching variable is already important, a new one to replace it has to be important
55
+ var isRoot = varDeclMapItem . parent . type === 'root' || varDeclMapItem . parent . selectors [ 0 ] === ':root' ;
56
+
57
+ var underScope = isNodeUnderScope ( decl . parent , varDeclMapItem . parent ) ;
58
+ var underScsopeIgnorePseudo = isNodeUnderScope ( decl . parent , varDeclMapItem . parent , ignorePseudoScope ) ;
59
+
60
+ //console.log(debugIndent, 'isNodeUnderScope', underScope, underScsopeIgnorePseudo, generateScopeList(varDeclMapItem.parent, true), varDeclMapItem.decl.value);
61
+
62
+ if (
63
+ underScsopeIgnorePseudo &&
64
+ // And if the currently matched declaration is `!important`, it will take another `!important` to override it
65
+ ( ! ( matchingVarDeclMapItem || { } ) . isImportant || varDeclMapItem . isImportant )
66
+ ) {
67
+ matchingVarDeclMapItem = varDeclMapItem ;
68
+ }
69
+ } ) ;
70
+
71
+ // Default to the calculatedInPlaceValue which might be a previous fallback, then try this declarations fallback
72
+ var replaceValue = ( matchingVarDeclMapItem || { } ) . calculatedInPlaceValue || ( function ( ) {
73
+ // Resolve `var` values in fallback
74
+ var fallbackValue = fallback ;
75
+ if ( fallback ) {
76
+ var fallbackDecl = decl . clone ( { parent : decl . parent , value : fallback } ) ;
77
+ fallbackValue = resolveValue ( fallbackDecl , map , false , /*internal*/ true ) . value ;
78
+ }
79
+
80
+ return fallbackValue ;
81
+ } ) ( ) ;
82
+ // Otherwise if the dependency health is good(no circular or self references), dive deeper and resolve
83
+ if ( matchingVarDeclMapItem !== undefined && ! gatherVariableDependencies ( variablesUsedInValue , map ) . hasCircularOrSelfReference ) {
84
+ // Splice the declaration parent onto the matching entry
85
+
86
+ var varDeclScopeList = generateScopeList ( decl . parent . parent , true ) ;
87
+ var innerMostAtRuleSelector = varDeclScopeList [ 0 ] . slice ( - 1 ) [ 0 ] ;
88
+ var nodeToSpliceParentOnto = findNodeAncestorWithSelector ( innerMostAtRuleSelector , matchingVarDeclMapItem . decl . parent ) ;
89
+ // See: `test/fixtures/cascade-with-calc-expression-on-nested-rules`
90
+ var matchingMimicDecl = cloneSpliceParentOntoNodeWhen ( matchingVarDeclMapItem . decl , decl . parent . parent , function ( ancestor ) {
91
+ return ancestor === nodeToSpliceParentOnto ;
92
+ } ) ;
93
+
94
+ replaceValue = resolveValue ( matchingMimicDecl , map , false , /*internal*/ true ) . value ;
67
95
}
68
- } ) ;
69
-
70
- // Default to the calculatedInPlaceValue which might be a previous fallback, then try this declarations fallback
71
- var replaceValue = ( matchingVarDeclMapItem || { } ) . calculatedInPlaceValue || ( function ( ) {
72
- // Resolve `var` values in fallback
73
- var fallbackValue = fallback ;
74
- if ( fallback ) {
75
- var fallbackDecl = decl . clone ( { parent : decl . parent , value : fallback } ) ;
76
- fallbackValue = resolveValue ( fallbackDecl , map , false , /*internal*/ true ) . value ;
96
+
97
+ isResultantValueUndefined = replaceValue === undefined ;
98
+ if ( isResultantValueUndefined ) {
99
+ warnings . push ( [ 'variable ' + variableName + ' is undefined and used without a fallback' , { node : decl } ] ) ;
77
100
}
78
-
79
- return fallbackValue ;
80
- } ) ( ) ;
81
- // Otherwise if the dependency health is good(no circular or self references), dive deeper and resolve
82
- if ( matchingVarDeclMapItem !== undefined && ! gatherVariableDependencies ( variablesUsedInValue , map ) . hasCircularOrSelfReference ) {
83
- // Splice the declaration parent onto the matching entry
84
-
85
- var varDeclScopeList = generateScopeList ( decl . parent . parent , true ) ;
86
- var innerMostAtRuleSelector = varDeclScopeList [ 0 ] . slice ( - 1 ) [ 0 ] ;
87
- var nodeToSpliceParentOnto = findNodeAncestorWithSelector ( innerMostAtRuleSelector , matchingVarDeclMapItem . decl . parent ) ;
88
- // See: `test/fixtures/cascade-with-calc-expression-on-nested-rules`
89
- var matchingMimicDecl = cloneSpliceParentOntoNodeWhen ( matchingVarDeclMapItem . decl , decl . parent . parent , function ( ancestor ) {
90
- return ancestor === nodeToSpliceParentOnto ;
91
- } ) ;
92
-
93
- replaceValue = resolveValue ( matchingMimicDecl , map , false , /*internal*/ true ) . value ;
94
- }
95
-
96
- isResultantValueUndefined = replaceValue === undefined ;
97
- if ( isResultantValueUndefined ) {
98
- warnings . push ( [ 'variable ' + variableName + ' is undefined and used without a fallback' , { node : decl } ] ) ;
99
- }
100
-
101
- //console.log(debugIndent, 'replaceValue', replaceValue);
102
-
103
- return replaceValue ;
104
- } ) ;
101
+
102
+ //console.log(debugIndent, 'replaceValue', replaceValue);
103
+
104
+ return replaceValue ;
105
+ } ) ;
106
+ }
105
107
106
108
return {
107
109
// The resolved value
0 commit comments