Mathias Bynens | 79e2cf0 | 2020-05-29 14:46:17 | [diff] [blame] | 1 | module.exports = function resolveNestedSelector(selector, node) { |
Nikolay Vitkov | 2a1b3b3 | 2025-01-03 10:18:46 | [diff] [blame] | 2 | var parent = node.parent; |
| 3 | var parentIsNestAtRule = parent.type === 'atrule' && parent.name === 'nest'; |
Mathias Bynens | 79e2cf0 | 2020-05-29 14:46:17 | [diff] [blame] | 4 | |
Nikolay Vitkov | 2a1b3b3 | 2025-01-03 10:18:46 | [diff] [blame] | 5 | if (parent.type === 'root') return [selector]; |
| 6 | if (parent.type !== 'rule' && !parentIsNestAtRule) return resolveNestedSelector(selector, parent); |
Mathias Bynens | 79e2cf0 | 2020-05-29 14:46:17 | [diff] [blame] | 7 | |
Nikolay Vitkov | 2a1b3b3 | 2025-01-03 10:18:46 | [diff] [blame] | 8 | var parentSelectors = (parentIsNestAtRule) |
| 9 | ? split(parent.params, ',', false).map((x) => x.trim()) |
| 10 | : parent.selectors; |
Mathias Bynens | 79e2cf0 | 2020-05-29 14:46:17 | [diff] [blame] | 11 | |
Nikolay Vitkov | 2a1b3b3 | 2025-01-03 10:18:46 | [diff] [blame] | 12 | var resolvedSelectors = parentSelectors.reduce(function(result, parentSelector) { |
| 13 | if (selector.indexOf('&') !== -1) { |
| 14 | var newlyResolvedSelectors = resolveNestedSelector(parentSelector, parent).map(function(resolvedParentSelector) { |
| 15 | return split(selector, '&', true).join(resolvedParentSelector); |
| 16 | }); |
| 17 | return result.concat(newlyResolvedSelectors); |
| 18 | } |
Mathias Bynens | 79e2cf0 | 2020-05-29 14:46:17 | [diff] [blame] | 19 | |
Nikolay Vitkov | 2a1b3b3 | 2025-01-03 10:18:46 | [diff] [blame] | 20 | var combinedSelector = [ parentSelector, selector ].join(' '); |
| 21 | return result.concat(resolveNestedSelector(combinedSelector, parent)); |
| 22 | }, []); |
Mathias Bynens | 79e2cf0 | 2020-05-29 14:46:17 | [diff] [blame] | 23 | |
Nikolay Vitkov | 2a1b3b3 | 2025-01-03 10:18:46 | [diff] [blame] | 24 | return resolvedSelectors; |
| 25 | } |
| 26 | |
| 27 | var blockPairs = { |
| 28 | '(': ')', |
| 29 | '[': ']', |
| 30 | '{': '}' |
| 31 | }; |
| 32 | |
| 33 | function split(string, separator, splitFunctions) { |
| 34 | var array = []; |
| 35 | var current = ''; |
| 36 | var split = false; |
| 37 | |
| 38 | var blockClose = []; |
| 39 | var inQuote = false; |
| 40 | var prevQuote = ''; |
| 41 | var escape = false; |
| 42 | |
| 43 | for (var letter of string) { |
| 44 | if (escape) { |
| 45 | escape = false; |
| 46 | } else if (letter === '\\') { |
| 47 | escape = true; |
| 48 | } else if (inQuote) { |
| 49 | if (letter === prevQuote) { |
| 50 | inQuote = false; |
| 51 | } |
| 52 | } else if (letter === '"' || letter === "'") { |
| 53 | inQuote = true; |
| 54 | prevQuote = letter; |
| 55 | } else if (letter === '(' || letter === '[' || letter === '{') { |
| 56 | blockClose.push(blockPairs[letter]); |
| 57 | } else if (letter === blockClose[blockClose.length - 1]) { |
| 58 | blockClose.pop(); |
| 59 | } else if (blockClose.length === 0 || (splitFunctions && blockClose.every((x) => x === ')'))) { |
| 60 | if (letter === separator) split = true; |
| 61 | } |
| 62 | |
| 63 | if (split) { |
| 64 | array.push(current); |
| 65 | current = ''; |
| 66 | split = false; |
| 67 | } else { |
| 68 | current += letter; |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | array.push(current); |
| 73 | return array; |
Mathias Bynens | 79e2cf0 | 2020-05-29 14:46:17 | [diff] [blame] | 74 | } |