1+ var balanced = require ( 'balanced-match' ) ;
2+
13var generateScopeList = require ( './generate-scope-list' ) ;
24var isNodeUnderScope = require ( './is-node-under-scope' ) ;
35var gatherVariableDependencies = require ( './gather-variable-dependencies' ) ;
46
57var findNodeAncestorWithSelector = require ( './find-node-ancestor-with-selector' ) ;
68var cloneSpliceParentOntoNodeWhen = require ( './clone-splice-parent-onto-node-when' ) ;
79
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 ) ] + ) / ) ;
1412
1513function toString ( value ) {
1614 return String ( value ) ;
@@ -27,26 +25,53 @@ function toString(value) {
2725var resolveValue = function ( decl , map , /*optional*/ ignorePseudoScope , /*internal debugging*/ _debugIsInternal ) {
2826 var debugIndent = _debugIsInternal ? '\t' : '' ;
2927
28+ var matchingVarDecl = undefined ;
3029 var resultantValue = toString ( decl . value ) ;
3130 var warnings = [ ] ;
3231
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
3646 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+
3854 var variablesUsedInValue = Object . keys ( variablesUsedInValueMap ) ;
3955
4056 //console.log(debugIndent, (_debugIsInternal ? '' : 'Try resolving'), generateScopeList(decl.parent, true), `ignorePseudoScope=${ignorePseudoScope}`, '------------------------');
4157
4258 // Resolve any var(...) substitutons
4359 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+
5075 ( map [ variableName ] || [ ] ) . forEach ( function ( varDeclMapItem ) {
5176 // Make sure the variable declaration came from the right spot
5277 // 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
97122 warnings . push ( [ 'variable ' + variableName + ' is undefined and used without a fallback' , { node : decl } ] ) ;
98123 }
99124
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+ }
104128
105129 return {
106130 // The resolved value
0 commit comments