@@ -10,8 +10,7 @@ var cloneSpliceParentOntoNodeWhen = require('./clone-splice-parent-onto-node-whe
1010// var() = var( <custom-property-name> [, <any-value> ]? )
1111// matches `name[, fallback]`, captures "name" and "fallback"
1212// 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 * \) / ) ;
1514
1615function toString ( value ) {
1716 return String ( value ) ;
@@ -42,66 +41,69 @@ var resolveValue = function(decl, map, /*optional*/ignorePseudoScope, /*internal
4241
4342 // Resolve any var(...) substitutons
4443 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' ;
5544
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 ;
6795 }
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 } ] ) ;
77100 }
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+ }
105107
106108 return {
107109 // The resolved value
0 commit comments