|
1 |
| -var matchRecursive = require('match-recursive'); |
| 1 | +var balanced = require('balanced-match'); |
2 | 2 |
|
3 | 3 | var generateScopeList = require('./generate-scope-list');
|
4 | 4 | var isNodeUnderScope = require('./is-node-under-scope');
|
@@ -43,74 +43,67 @@ var resolveValue = function(decl, map, /*optional*/ignorePseudoScope, /*internal
|
43 | 43 | // var() = var( <custom-property-name> [, <any-value> ]? )
|
44 | 44 | // matches `name[, fallback]`, captures "name" and "fallback"
|
45 | 45 | // See: http://dev.w3.org/csswg/css-variables/#funcdef-var
|
46 |
| - var matches = null; |
47 |
| - // iterate over possible recursive matches |
48 |
| - while ((matches = matchRecursive(resultantValue, 'var(...)')).length) { |
49 |
| - // var originalDeclaration = matches.shift(); // get what was matched |
50 |
| - |
51 |
| - // iterate over found var() occurences (some declaration may have multiple var() nested) |
52 |
| - matches.forEach(function (match) { |
53 |
| - match = match.split(','); |
54 |
| - match = [ match.shift(), match.join(',') ].filter(item => item) // clear empty items |
55 |
| - |
56 |
| - var [ variableName, fallback ] = match.map(item => item.trim()) |
57 |
| - |
58 |
| - var matchingVarDeclMapItem; |
59 |
| - (map[variableName] || []).forEach(function(varDeclMapItem) { |
60 |
| - // Make sure the variable declaration came from the right spot |
61 |
| - // And if the current matching variable is already important, a new one to replace it has to be important |
62 |
| - var isRoot = varDeclMapItem.parent.type === 'root' || varDeclMapItem.parent.selectors[0] === ':root'; |
63 |
| - |
64 |
| - var underScope = isNodeUnderScope(decl.parent, varDeclMapItem.parent); |
65 |
| - var underScsopeIgnorePseudo = isNodeUnderScope(decl.parent, varDeclMapItem.parent, ignorePseudoScope); |
66 |
| - |
67 |
| - //console.log(debugIndent, 'isNodeUnderScope', underScope, underScsopeIgnorePseudo, generateScopeList(varDeclMapItem.parent, true), varDeclMapItem.decl.value); |
68 |
| - |
69 |
| - if( |
70 |
| - underScsopeIgnorePseudo && |
71 |
| - // And if the currently matched declaration is `!important`, it will take another `!important` to override it |
72 |
| - (!(matchingVarDeclMapItem || {}).isImportant || varDeclMapItem.isImportant) |
73 |
| - ) { |
74 |
| - matchingVarDeclMapItem = varDeclMapItem; |
75 |
| - } |
76 |
| - }); |
77 |
| - |
78 |
| - // Default to the calculatedInPlaceValue which might be a previous fallback, then try this declarations fallback |
79 |
| - var replaceValue = (matchingVarDeclMapItem || {}).calculatedInPlaceValue || (function() { |
80 |
| - // Resolve `var` values in fallback |
81 |
| - var fallbackValue = fallback; |
82 |
| - if(fallback) { |
83 |
| - var fallbackDecl = decl.clone({ parent: decl.parent, value: fallback }); |
84 |
| - fallbackValue = resolveValue(fallbackDecl, map, false, /*internal*/true).value; |
85 |
| - } |
86 |
| - |
87 |
| - return fallbackValue; |
88 |
| - })(); |
89 |
| - // Otherwise if the dependency health is good(no circular or self references), dive deeper and resolve |
90 |
| - if(matchingVarDeclMapItem !== undefined && !gatherVariableDependencies(variablesUsedInValue, map).hasCircularOrSelfReference) { |
91 |
| - // Splice the declaration parent onto the matching entry |
92 |
| - |
93 |
| - var varDeclScopeList = generateScopeList(decl.parent.parent, true); |
94 |
| - var innerMostAtRuleSelector = varDeclScopeList[0].slice(-1)[0]; |
95 |
| - var nodeToSpliceParentOnto = findNodeAncestorWithSelector(innerMostAtRuleSelector, matchingVarDeclMapItem.decl.parent); |
96 |
| - // See: `test/fixtures/cascade-with-calc-expression-on-nested-rules` |
97 |
| - var matchingMimicDecl = cloneSpliceParentOntoNodeWhen(matchingVarDeclMapItem.decl, decl.parent.parent, function(ancestor) { |
98 |
| - return ancestor === nodeToSpliceParentOnto; |
99 |
| - }); |
100 |
| - |
101 |
| - replaceValue = resolveValue(matchingMimicDecl, map, false, /*internal*/true).value; |
| 46 | + var match; |
| 47 | + while (match = balanced('var(', ')', resultantValue)) { |
| 48 | + var matchingVarDeclMapItem = undefined; |
| 49 | + |
| 50 | + // split comma to find variable name and fallback value |
| 51 | + match.body = match.body.split(','); |
| 52 | + // get variable name and fallback, filtering empty items |
| 53 | + var [ variableName, fallback ] = [ match.body.shift(), match.body.join(',') ].map(item => item.trim()).filter(item => !!item); |
| 54 | + |
| 55 | + (map[variableName] || []).forEach(function(varDeclMapItem) { |
| 56 | + // Make sure the variable declaration came from the right spot |
| 57 | + // And if the current matching variable is already important, a new one to replace it has to be important |
| 58 | + var isRoot = varDeclMapItem.parent.type === 'root' || varDeclMapItem.parent.selectors[0] === ':root'; |
| 59 | + |
| 60 | + var underScope = isNodeUnderScope(decl.parent, varDeclMapItem.parent); |
| 61 | + var underScsopeIgnorePseudo = isNodeUnderScope(decl.parent, varDeclMapItem.parent, ignorePseudoScope); |
| 62 | + |
| 63 | + //console.log(debugIndent, 'isNodeUnderScope', underScope, underScsopeIgnorePseudo, generateScopeList(varDeclMapItem.parent, true), varDeclMapItem.decl.value); |
| 64 | + |
| 65 | + if( |
| 66 | + underScsopeIgnorePseudo && |
| 67 | + // And if the currently matched declaration is `!important`, it will take another `!important` to override it |
| 68 | + (!(matchingVarDeclMapItem || {}).isImportant || varDeclMapItem.isImportant) |
| 69 | + ) { |
| 70 | + matchingVarDeclMapItem = varDeclMapItem; |
102 | 71 | }
|
| 72 | + }); |
103 | 73 |
|
104 |
| - isResultantValueUndefined = replaceValue === undefined; |
105 |
| - if(isResultantValueUndefined) { |
106 |
| - warnings.push(['variable ' + variableName + ' is undefined and used without a fallback', { node: decl }]); |
| 74 | + // Default to the calculatedInPlaceValue which might be a previous fallback, then try this declarations fallback |
| 75 | + var replaceValue = (matchingVarDeclMapItem || {}).calculatedInPlaceValue || (function() { |
| 76 | + // Resolve `var` values in fallback |
| 77 | + var fallbackValue = fallback; |
| 78 | + if(fallback) { |
| 79 | + var fallbackDecl = decl.clone({ parent: decl.parent, value: fallback }); |
| 80 | + fallbackValue = resolveValue(fallbackDecl, map, false, /*internal*/true).value; |
107 | 81 | }
|
108 | 82 |
|
109 |
| - // replace original declaration |
110 |
| - resultantValue = resultantValue.replace(`var(${match.join(',')})`, replaceValue) |
| 83 | + return fallbackValue; |
| 84 | + })(); |
| 85 | + // Otherwise if the dependency health is good(no circular or self references), dive deeper and resolve |
| 86 | + if(matchingVarDeclMapItem !== undefined && !gatherVariableDependencies(variablesUsedInValue, map).hasCircularOrSelfReference) { |
| 87 | + // Splice the declaration parent onto the matching entry |
| 88 | + |
| 89 | + var varDeclScopeList = generateScopeList(decl.parent.parent, true); |
| 90 | + var innerMostAtRuleSelector = varDeclScopeList[0].slice(-1)[0]; |
| 91 | + var nodeToSpliceParentOnto = findNodeAncestorWithSelector(innerMostAtRuleSelector, matchingVarDeclMapItem.decl.parent); |
| 92 | + // See: `test/fixtures/cascade-with-calc-expression-on-nested-rules` |
| 93 | + var matchingMimicDecl = cloneSpliceParentOntoNodeWhen(matchingVarDeclMapItem.decl, decl.parent.parent, function(ancestor) { |
| 94 | + return ancestor === nodeToSpliceParentOnto; |
| 95 | + }); |
111 | 96 |
|
112 |
| - //console.log(debugIndent, 'replaceValue', replaceValue); |
113 |
| - }); |
| 97 | + replaceValue = resolveValue(matchingMimicDecl, map, false, /*internal*/true).value; |
| 98 | + } |
| 99 | + |
| 100 | + isResultantValueUndefined = replaceValue === undefined; |
| 101 | + if(isResultantValueUndefined) { |
| 102 | + warnings.push(['variable ' + variableName + ' is undefined and used without a fallback', { node: decl }]); |
| 103 | + } |
| 104 | + |
| 105 | + // replace original declaration |
| 106 | + resultantValue = `${match.pre || ''}${replaceValue}${match.post || ''}`; |
114 | 107 | }
|
115 | 108 |
|
116 | 109 | return {
|
|
0 commit comments