|
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