var isMergeable = require('./is-mergeable'); var sortSelectors = require('../level-1/sort-selectors'); var tidyRules = require('../level-1/tidy-rules'); var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel; var serializeBody = require('../../writer/one-time').body; var serializeRules = require('../../writer/one-time').rules; var Token = require('../../tokenizer/token'); function unsafeSelector(value) { return /\.|\*| :/.test(value); } function isBemElement(token) { var asString = serializeRules(token[1]); return asString.indexOf('__') > -1 || asString.indexOf('--') > -1; } function withoutModifier(selector) { return selector.replace(/--[^ ,>\+~:]+/g, ''); } function removeAnyUnsafeElements(left, candidates) { var leftSelector = withoutModifier(serializeRules(left[1])); for (var body in candidates) { var right = candidates[body]; var rightSelector = withoutModifier(serializeRules(right[1])); if (rightSelector.indexOf(leftSelector) > -1 || leftSelector.indexOf(rightSelector) > -1) delete candidates[body]; } } function mergeNonAdjacentByBody(tokens, context) { var options = context.options; var mergeSemantically = options.level[OptimizationLevel.Two].mergeSemantically; var adjacentSpace = options.compatibility.selectors.adjacentSpace; var selectorsSortingMethod = options.level[OptimizationLevel.One].selectorsSortingMethod; var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses; var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements; var multiplePseudoMerging = options.compatibility.selectors.multiplePseudoMerging; var candidates = {}; for (var i = tokens.length - 1; i >= 0; i--) { var token = tokens[i]; if (token[0] != Token.RULE) continue; if (token[2].length > 0 && (!mergeSemantically && unsafeSelector(serializeRules(token[1])))) candidates = {}; if (token[2].length > 0 && mergeSemantically && isBemElement(token)) removeAnyUnsafeElements(token, candidates); var candidateBody = serializeBody(token[2]); var oldToken = candidates[candidateBody]; if (oldToken && isMergeable(serializeRules(token[1]), mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging) && isMergeable(serializeRules(oldToken[1]), mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging)) { if (token[2].length > 0) { token[1] = tidyRules(oldToken[1].concat(token[1]), false, adjacentSpace, false, context.warnings); token[1] = token[1].length > 1 ? sortSelectors(token[1], selectorsSortingMethod) : token[1]; } else { token[1] = oldToken[1].concat(token[1]); } oldToken[2] = []; candidates[candidateBody] = null; } candidates[serializeBody(token[2])] = token; } } module.exports = mergeNonAdjacentByBody;