|
|
var isMergeable = require('./is-mergeable');
var optimizeProperties = require('./properties/optimize');
var cloneArray = require('../../utils/clone-array');
var Token = require('../../tokenizer/token');
var serializeBody = require('../../writer/one-time').body; var serializeRules = require('../../writer/one-time').rules;
function reduceNonAdjacent(tokens, context) { var options = context.options; var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses; var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements; var multiplePseudoMerging = options.compatibility.selectors.multiplePseudoMerging; var candidates = {}; var repeated = [];
for (var i = tokens.length - 1; i >= 0; i--) { var token = tokens[i];
if (token[0] != Token.RULE) { continue; } else if (token[2].length === 0) { continue; }
var selectorAsString = serializeRules(token[1]); var isComplexAndNotSpecial = token[1].length > 1 && isMergeable(selectorAsString, mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging); var wrappedSelectors = wrappedSelectorsFrom(token[1]); var selectors = isComplexAndNotSpecial ? [selectorAsString].concat(wrappedSelectors) : [selectorAsString];
for (var j = 0, m = selectors.length; j < m; j++) { var selector = selectors[j];
if (!candidates[selector]) candidates[selector] = []; else repeated.push(selector);
candidates[selector].push({ where: i, list: wrappedSelectors, isPartial: isComplexAndNotSpecial && j > 0, isComplex: isComplexAndNotSpecial && j === 0 }); } }
reduceSimpleNonAdjacentCases(tokens, repeated, candidates, options, context); reduceComplexNonAdjacentCases(tokens, candidates, options, context); }
function wrappedSelectorsFrom(list) { var wrapped = [];
for (var i = 0; i < list.length; i++) { wrapped.push([list[i][1]]); }
return wrapped; }
function reduceSimpleNonAdjacentCases(tokens, repeated, candidates, options, context) { function filterOut(idx, bodies) { return data[idx].isPartial && bodies.length === 0; }
function reduceBody(token, newBody, processedCount, tokenIdx) { if (!data[processedCount - tokenIdx - 1].isPartial) token[2] = newBody; }
for (var i = 0, l = repeated.length; i < l; i++) { var selector = repeated[i]; var data = candidates[selector];
reduceSelector(tokens, data, { filterOut: filterOut, callback: reduceBody }, options, context); } }
function reduceComplexNonAdjacentCases(tokens, candidates, options, context) { var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses; var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements; var multiplePseudoMerging = options.compatibility.selectors.multiplePseudoMerging; var localContext = {};
function filterOut(idx) { return localContext.data[idx].where < localContext.intoPosition; }
function collectReducedBodies(token, newBody, processedCount, tokenIdx) { if (tokenIdx === 0) localContext.reducedBodies.push(newBody); }
allSelectors: for (var complexSelector in candidates) { var into = candidates[complexSelector]; if (!into[0].isComplex) continue;
var intoPosition = into[into.length - 1].where; var intoToken = tokens[intoPosition]; var reducedBodies = [];
var selectors = isMergeable(complexSelector, mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging) ? into[0].list : [complexSelector];
localContext.intoPosition = intoPosition; localContext.reducedBodies = reducedBodies;
for (var j = 0, m = selectors.length; j < m; j++) { var selector = selectors[j]; var data = candidates[selector];
if (data.length < 2) continue allSelectors;
localContext.data = data;
reduceSelector(tokens, data, { filterOut: filterOut, callback: collectReducedBodies }, options, context);
if (serializeBody(reducedBodies[reducedBodies.length - 1]) != serializeBody(reducedBodies[0])) continue allSelectors; }
intoToken[2] = reducedBodies[0]; } }
function reduceSelector(tokens, data, context, options, outerContext) { var bodies = []; var bodiesAsList = []; var processedTokens = [];
for (var j = data.length - 1; j >= 0; j--) { if (context.filterOut(j, bodies)) continue;
var where = data[j].where; var token = tokens[where]; var clonedBody = cloneArray(token[2]);
bodies = bodies.concat(clonedBody); bodiesAsList.push(clonedBody); processedTokens.push(where); }
optimizeProperties(bodies, true, false, outerContext);
var processedCount = processedTokens.length; var propertyIdx = bodies.length - 1; var tokenIdx = processedCount - 1;
while (tokenIdx >= 0) { if ((tokenIdx === 0 || (bodies[propertyIdx] && bodiesAsList[tokenIdx].indexOf(bodies[propertyIdx]) > -1)) && propertyIdx > -1) { propertyIdx--; continue; }
var newBody = bodies.splice(propertyIdx + 1); context.callback(tokens[processedTokens[tokenIdx]], newBody, processedCount, tokenIdx);
tokenIdx--; } }
module.exports = reduceNonAdjacent;
|