| import { generate } from 'css-tree'; |
| import specificity from './specificity.js'; |
| |
| const nonFreezePseudoElements = new Set([ |
| 'first-letter', |
| 'first-line', |
| 'after', |
| 'before' |
| ]); |
| const nonFreezePseudoClasses = new Set([ |
| 'link', |
| 'visited', |
| 'hover', |
| 'active', |
| 'first-letter', |
| 'first-line', |
| 'after', |
| 'before' |
| ]); |
| |
| export default function processSelector(node, usageData) { |
| const pseudos = new Set(); |
| |
| node.prelude.children.forEach(function(simpleSelector) { |
| let tagName = '*'; |
| let scope = 0; |
| |
| simpleSelector.children.forEach(function(node) { |
| switch (node.type) { |
| case 'ClassSelector': |
| if (usageData && usageData.scopes) { |
| const classScope = usageData.scopes[node.name] || 0; |
| |
| if (scope !== 0 && classScope !== scope) { |
| throw new Error('Selector can\'t has classes from different scopes: ' + generate(simpleSelector)); |
| } |
| |
| scope = classScope; |
| } |
| |
| break; |
| |
| case 'PseudoClassSelector': { |
| const name = node.name.toLowerCase(); |
| |
| if (!nonFreezePseudoClasses.has(name)) { |
| pseudos.add(`:${name}`); |
| } |
| |
| break; |
| } |
| |
| case 'PseudoElementSelector': { |
| const name = node.name.toLowerCase(); |
| |
| if (!nonFreezePseudoElements.has(name)) { |
| pseudos.add(`::${name}`); |
| } |
| |
| break; |
| } |
| |
| case 'TypeSelector': |
| tagName = node.name.toLowerCase(); |
| break; |
| |
| case 'AttributeSelector': |
| if (node.flags) { |
| pseudos.add(`[${node.flags.toLowerCase()}]`); |
| } |
| |
| break; |
| |
| case 'Combinator': |
| tagName = '*'; |
| break; |
| } |
| }); |
| |
| simpleSelector.compareMarker = specificity(simpleSelector).toString(); |
| simpleSelector.id = null; // pre-init property to avoid multiple hidden class |
| simpleSelector.id = generate(simpleSelector); |
| |
| if (scope) { |
| simpleSelector.compareMarker += ':' + scope; |
| } |
| |
| if (tagName !== '*') { |
| simpleSelector.compareMarker += ',' + tagName; |
| } |
| }); |
| |
| // add property to all rule nodes to avoid multiple hidden class |
| node.pseudoSignature = pseudos.size > 0 |
| ? [...pseudos].sort().join(',') |
| : false; |
| }; |