From 56e089e07049244ca6fcf6d7e99ec6b6140bcd42 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowicz Date: Sun, 21 Jun 2015 12:09:06 +0100 Subject: [PATCH] Extracts 'reduce non adjacent' optimization into a module. --- lib/selectors/advanced.js | 156 +------------------- lib/selectors/reduce-non-adjacent.js | 159 +++++++++++++++++++++ test/integration-test.js | 92 ------------ test/selectors/advanced-test.js | 16 --- test/selectors/reduce-non-adjacent-test.js | 121 ++++++++++++++++ 5 files changed, 282 insertions(+), 262 deletions(-) create mode 100644 lib/selectors/reduce-non-adjacent.js create mode 100644 test/selectors/reduce-non-adjacent-test.js diff --git a/lib/selectors/advanced.js b/lib/selectors/advanced.js index ef6c4e74..cdfa961f 100644 --- a/lib/selectors/advanced.js +++ b/lib/selectors/advanced.js @@ -10,6 +10,7 @@ var stringifySelectors = require('../stringifier/one-time').selectors; var removeDuplicates = require('./remove-duplicates'); var mergeAdjacent = require('./merge-adjacent'); +var reduceNonAdjacent = require('./reduce-non-adjacent'); function AdvancedOptimizer(options, context) { this.options = options; @@ -28,159 +29,6 @@ AdvancedOptimizer.prototype.isSpecial = function (selector) { return this.options.compatibility.selectors.special.test(selector); }; -AdvancedOptimizer.prototype.reduceNonAdjacent = function (tokens) { - var candidates = {}; - var repeated = []; - - for (var i = tokens.length - 1; i >= 0; i--) { - var token = tokens[i]; - - if (token[0] != 'selector') - continue; - if (token[2].length === 0) - continue; - - var selectorAsString = stringifySelectors(token[1]); - var isComplexAndNotSpecial = token[1].length > 1 && !this.isSpecial(selectorAsString); - var selectors = isComplexAndNotSpecial ? - [selectorAsString].concat(token[1]) : - [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: token[1], - isPartial: isComplexAndNotSpecial && j > 0, - isComplex: isComplexAndNotSpecial && j === 0 - }); - } - } - - this.reduceSimpleNonAdjacentCases(tokens, repeated, candidates); - this.reduceComplexNonAdjacentCases(tokens, candidates); -}; - -AdvancedOptimizer.prototype.reduceSimpleNonAdjacentCases = function (tokens, repeated, candidates) { - 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]; - - this.reduceSelector(tokens, selector, data, { - filterOut: filterOut, - callback: reduceBody - }); - } -}; - -AdvancedOptimizer.prototype.reduceComplexNonAdjacentCases = function (tokens, candidates) { - 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 = this.isSpecial(complexSelector) ? - [complexSelector] : - into[0].list; - - 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; - - this.reduceSelector(tokens, selector, data, { - filterOut: filterOut, - callback: collectReducedBodies - }); - - if (stringifyBody(reducedBodies[reducedBodies.length - 1]) != stringifyBody(reducedBodies[0])) - continue allSelectors; - } - - intoToken[2] = reducedBodies[0]; - } -}; - -AdvancedOptimizer.prototype.reduceSelector = function (tokens, selector, data, options) { - var bodies = []; - var bodiesAsList = []; - var joinsAt = []; - var processedTokens = []; - - for (var j = data.length - 1, m = 0; j >= 0; j--) { - if (options.filterOut(j, bodies)) - continue; - - var where = data[j].where; - var token = tokens[where]; - - bodies = bodies.concat(token[2]); - bodiesAsList.push(token[2]); - processedTokens.push(where); - } - - for (j = 0, m = bodiesAsList.length; j < m; j++) { - if (bodiesAsList[j].length > 0) - joinsAt.push((joinsAt[j - 1] || 0) + bodiesAsList[j].length); - } - - optimizeProperties(selector, bodies, joinsAt, false, this.options, this.validator); - - 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); - options.callback(tokens[processedTokens[tokenIdx]], newBody, processedCount, tokenIdx); - - tokenIdx--; - } -}; - AdvancedOptimizer.prototype.mergeNonAdjacentBySelector = function (tokens) { var allSelectors = {}; var repeatedSelectors = []; @@ -754,7 +602,7 @@ AdvancedOptimizer.prototype.optimize = function (tokens) { removeDuplicates(tokens); mergeAdjacent(tokens, self.options, self.validator); - self.reduceNonAdjacent(tokens); + reduceNonAdjacent(tokens, self.options, self.validator); self.mergeNonAdjacentBySelector(tokens); self.mergeNonAdjacentByBody(tokens); diff --git a/lib/selectors/reduce-non-adjacent.js b/lib/selectors/reduce-non-adjacent.js new file mode 100644 index 00000000..c3d7efb7 --- /dev/null +++ b/lib/selectors/reduce-non-adjacent.js @@ -0,0 +1,159 @@ +var optimizeProperties = require('../properties/optimizer'); +var stringifyBody = require('../stringifier/one-time').body; +var stringifySelectors = require('../stringifier/one-time').selectors; +var isSpecial = require('./is-special'); + +function reduceNonAdjacent(tokens, options, validator) { + var candidates = {}; + var repeated = []; + + for (var i = tokens.length - 1; i >= 0; i--) { + var token = tokens[i]; + + if (token[0] != 'selector') + continue; + if (token[2].length === 0) + continue; + + var selectorAsString = stringifySelectors(token[1]); + var isComplexAndNotSpecial = token[1].length > 1 && !isSpecial(options, selectorAsString); + var selectors = isComplexAndNotSpecial ? + [selectorAsString].concat(token[1]) : + [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: token[1], + isPartial: isComplexAndNotSpecial && j > 0, + isComplex: isComplexAndNotSpecial && j === 0 + }); + } + } + + reduceSimpleNonAdjacentCases(tokens, repeated, candidates, options, validator); + reduceComplexNonAdjacentCases(tokens, candidates, options, validator); +} + +function reduceSimpleNonAdjacentCases(tokens, repeated, candidates, options, validator) { + 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, selector, data, { + filterOut: filterOut, + callback: reduceBody + }, options, validator); + } +} + +function reduceComplexNonAdjacentCases(tokens, candidates, options, validator) { + 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 = isSpecial(options, complexSelector) ? + [complexSelector] : + into[0].list; + + 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, selector, data, { + filterOut: filterOut, + callback: collectReducedBodies + }, options, validator); + + if (stringifyBody(reducedBodies[reducedBodies.length - 1]) != stringifyBody(reducedBodies[0])) + continue allSelectors; + } + + intoToken[2] = reducedBodies[0]; + } +} + +function reduceSelector(tokens, selector, data, context, options, validator) { + var bodies = []; + var bodiesAsList = []; + var joinsAt = []; + var processedTokens = []; + + for (var j = data.length - 1, m = 0; j >= 0; j--) { + if (context.filterOut(j, bodies)) + continue; + + var where = data[j].where; + var token = tokens[where]; + + bodies = bodies.concat(token[2]); + bodiesAsList.push(token[2]); + processedTokens.push(where); + } + + for (j = 0, m = bodiesAsList.length; j < m; j++) { + if (bodiesAsList[j].length > 0) + joinsAt.push((joinsAt[j - 1] || 0) + bodiesAsList[j].length); + } + + optimizeProperties(selector, bodies, joinsAt, false, options, validator); + + 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; diff --git a/test/integration-test.js b/test/integration-test.js index eb8487d7..1a12fed5 100644 --- a/test/integration-test.js +++ b/test/integration-test.js @@ -2158,98 +2158,6 @@ vows.describe('integration tests') ] }, { aggressiveMerging: false }) ) - .addBatch( - optimizerContext('same non-adjacent selectors', { - 'with one redefined property': [ - 'a{color:red;display:block}.one{color:red}a{color:#fff;margin:2px}', - '.one{color:red}a{display:block;color:#fff;margin:2px}' - ], - 'with intentionally redefined properties on joins': [ - 'a{display:inline-block;display:-moz-inline-box;color:red}.one{margin:12px}a{color:#fff;margin:2px}', - '.one{margin:12px}a{display:inline-block;display:-moz-inline-box;color:#fff;margin:2px}' - ], - 'with intentionally redefined properties on multiple joins': [ - 'a{color:red}.one{font-size:12px}a{color:#fff;margin:2px}.two{margin:10px}a{margin:0}', - '.one{font-size:12px}.two{margin:10px}a{color:#fff;margin:0}' - ], - 'with all redefined properties': [ - 'a{color:red;display:block}.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}', - '.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}' - ], - 'many with all redefined properties': [ - 'a{padding:10px}.zero{color:transparent}a{color:red;display:block}.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}', - '.zero{color:transparent}.one{font-size:12px}a{padding:10px;color:#fff;display:inline-block;margin:2px}' - ], - 'when overriden by an empty selector': [ - 'a{padding:10px}.one{color:red}a{}', - 'a{padding:10px}.one{color:red}' - ], - 'when overriden by a complex selector': [ - 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}', - '.one,a,p{color:red}a{margin:0}a,p{padding:0}' - ], - 'when overriden by complex selectors': [ - 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}.one,a{color:#fff}', - 'a{margin:0}a,p{color:red;padding:0}.one,a{color:#fff}' - ], - 'when complex selector overriden by simple selectors': [ - 'a,p{margin:0;color:red}a{color:#fff}', - 'a,p{margin:0;color:red}a{color:#fff}' - ], - 'when complex selector overriden by complex and simple selectors': [ - 'a,p{margin:0;color:red}a{color:#fff}a,p{color:#00f}p{color:#0f0}', - 'a,p{margin:0;color:#00f}p{color:#0f0}' - ], - 'when complex selector overriden by complex selectors': [ - '.one>.two,.three{color:red;line-height:1rem}#zero,.one>.two,.three,.www{color:#fff;margin:0}a{color:red}.one>.two,.three{line-height:2rem;font-size:1.5rem}', - '#zero,.one>.two,.three,.www{color:#fff;margin:0}a{color:red}.one>.two,.three{line-height:2rem;font-size:1.5rem}' - ], - 'when undefined is used as a value': [ - '.one{text-shadow:undefined}p{font-size:14px}.one{font-size:12px}', - 'p{font-size:14px}.one{text-shadow:undefined;font-size:12px}' - ], - 'when undefined is used as a value with reduction': [ - '.one{text-shadow:undefined}p{color:red}.one{font-size:12px;text-shadow:none}', - 'p{color:red}.one{font-size:12px;text-shadow:none}' - ], - 'when overriden with a browser specific selector': [ - 'a{color:red}p{display:block}::-moz-selection,a{color:#fff}', - 'a{color:red}p{display:block}::-moz-selection,a{color:#fff}' - ], - 'when same browser specific selector more than once': [ - 'a,::-moz-selection{color:red}p{display:block}a,::-moz-selection{color:#fff}', - 'p{display:block}::-moz-selection,a{color:#fff}' - ], - 'with full property comparison': [ - '.one{height:7rem}.two{color:#fff}.one{line-height:7rem;color:red}', - '.two{color:#fff}.one{height:7rem;line-height:7rem;color:red}' - ], - 'with two intermediate, non-overriding selectors': [ - '.one{color:red;margin:0}.two{color:#fff}.one{font-size:12px}', - '.one{color:red;margin:0;font-size:12px}.two{color:#fff}' - ], - 'with two intermediate, overriding more specific selectors': [ - '.one{color:red;margin:0}.two{font:12px serif}.one{font-size:12px}', - '.two{font:12px serif}.one{color:red;margin:0;font-size:12px}' - ], - 'with granular selectors from the same shorthand': [ - '.one{color:red;margin:0}.two{font-weight:700}.one{font-size:12px}', - '.one{color:red;margin:0;font-size:12px}.two{font-weight:700}' - ], - 'with three intermediate, non-overriding selectors': [ - '.one{color:red;margin:0}.two{color:#fff}.one{font-size:12px}.three{color:#000}.one{padding:0}', - '.one{color:red;margin:0;font-size:12px;padding:0}.two{color:#fff}.three{color:#000}' - ], - 'successive selectors': [ - 'footer,header{top:1.25em;bottom:1.25em}header{top:2.5em}footer{bottom:2.5em}', - 'footer,header{top:1.25em;bottom:1.25em}header{top:2.5em}footer{bottom:2.5em}' - ], - 'over a @media block': [ - '.one{color:red;margin:0}@media{.two{font-weight:700}}.one{font-size:12px}', - '.one{color:red;margin:0;font-size:12px}@media{.two{font-weight:700}}' - ] - }) - ) .addBatch( optimizerContext('rerun optimizers', { 'selectors reducible once': [ diff --git a/test/selectors/advanced-test.js b/test/selectors/advanced-test.js index f47b11c8..0ad99608 100644 --- a/test/selectors/advanced-test.js +++ b/test/selectors/advanced-test.js @@ -208,14 +208,6 @@ vows.describe('advanced optimizer') 'repeated' : [ 'a{color:red;color:red}', 'a{color:red}' - ], - 'non-adjacent': [ - 'a{color:red;display:block}.one{margin:12px}a{color:#fff;margin:2px}', - '.one{margin:12px}a{display:block;color:#fff;margin:2px}' - ], - 'non-adjacent with multi selectors': [ - 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}', - '.one,a,p{color:red}a{margin:0}a,p{padding:0}' ] }, { advanced: true, aggressiveMerging: true }) ) @@ -232,10 +224,6 @@ vows.describe('advanced optimizer') 'repeated' : [ 'a{color:red;color:red}', 'a{color:red}' - ], - 'non-adjacent with multi selectors': [ - 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}', - '.one,a,p{color:red}a{padding:10px;margin:0}a,p{padding:0}' ] }, { advanced: true, aggressiveMerging: false }) ) @@ -244,10 +232,6 @@ vows.describe('advanced optimizer') 'repeated' : [ 'a{color:red;color:red}', 'a{color:red;color:red}' - ], - 'non-adjacent': [ - 'a{color:red;display:block}.one{font-size:12px}a{color:#fff;margin:2px}', - 'a{color:red;display:block}.one{font-size:12px}a{color:#fff;margin:2px}' ] }, { advanced: false }) ) diff --git a/test/selectors/reduce-non-adjacent-test.js b/test/selectors/reduce-non-adjacent-test.js new file mode 100644 index 00000000..848e3432 --- /dev/null +++ b/test/selectors/reduce-non-adjacent-test.js @@ -0,0 +1,121 @@ +var vows = require('vows'); +var optimizerContext = require('../test-helper').optimizerContext; + +vows.describe('remove duplicates') + .addBatch( + optimizerContext('advanced on', { + 'single selectors': [ + 'a{color:red;display:block}.one{margin:12px}a{color:#fff;margin:2px}', + '.one{margin:12px}a{display:block;color:#fff;margin:2px}' + ], + 'multiple selectors': [ + 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}', + '.one,a,p{color:red}a{margin:0}a,p{padding:0}' + ], + 'with one redefined property': [ + 'a{color:red;display:block}.one{color:red}a{color:#fff;margin:2px}', + '.one{color:red}a{display:block;color:#fff;margin:2px}' + ], + 'with intentionally redefined properties on joins': [ + 'a{display:inline-block;display:-moz-inline-box;color:red}.one{margin:12px}a{color:#fff;margin:2px}', + '.one{margin:12px}a{display:inline-block;display:-moz-inline-box;color:#fff;margin:2px}' + ], + 'with intentionally redefined properties on multiple joins': [ + 'a{color:red}.one{font-size:12px}a{color:#fff;margin:2px}.two{margin:10px}a{margin:0}', + '.one{font-size:12px}.two{margin:10px}a{color:#fff;margin:0}' + ], + 'with all redefined properties': [ + 'a{color:red;display:block}.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}', + '.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}' + ], + 'many with all redefined properties': [ + 'a{padding:10px}.zero{color:transparent}a{color:red;display:block}.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}', + '.zero{color:transparent}.one{font-size:12px}a{padding:10px;color:#fff;display:inline-block;margin:2px}' + ], + 'when overriden by an empty selector': [ + 'a{padding:10px}.one{color:red}a{}', + 'a{padding:10px}.one{color:red}' + ], + 'when overriden by a complex selector': [ + 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}', + '.one,a,p{color:red}a{margin:0}a,p{padding:0}' + ], + 'when overriden by complex selectors': [ + 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}.one,a{color:#fff}', + 'a{margin:0}a,p{color:red;padding:0}.one,a{color:#fff}' + ], + 'when complex selector overriden by simple selectors': [ + 'a,p{margin:0;color:red}a{color:#fff}', + 'a,p{margin:0;color:red}a{color:#fff}' + ], + 'when complex selector overriden by complex and simple selectors': [ + 'a,p{margin:0;color:red}a{color:#fff}a,p{color:#00f}p{color:#0f0}', + 'a,p{margin:0;color:#00f}p{color:#0f0}' + ], + 'when complex selector overriden by complex selectors': [ + '.one>.two,.three{color:red;line-height:1rem}#zero,.one>.two,.three,.www{color:#fff;margin:0}a{color:red}.one>.two,.three{line-height:2rem;font-size:1.5rem}', + '#zero,.one>.two,.three,.www{color:#fff;margin:0}a{color:red}.one>.two,.three{line-height:2rem;font-size:1.5rem}' + ], + 'when undefined is used as a value': [ + '.one{text-shadow:undefined}p{font-size:14px}.one{font-size:12px}', + 'p{font-size:14px}.one{text-shadow:undefined;font-size:12px}' + ], + 'when undefined is used as a value with reduction': [ + '.one{text-shadow:undefined}p{color:red}.one{font-size:12px;text-shadow:none}', + 'p{color:red}.one{font-size:12px;text-shadow:none}' + ], + 'when overriden with a browser specific selector': [ + 'a{color:red}p{display:block}::-moz-selection,a{color:#fff}', + 'a{color:red}p{display:block}::-moz-selection,a{color:#fff}' + ], + 'when same browser specific selector more than once': [ + 'a,::-moz-selection{color:red}p{display:block}a,::-moz-selection{color:#fff}', + 'p{display:block}::-moz-selection,a{color:#fff}' + ], + 'with full property comparison': [ + '.one{height:7rem}.two{color:#fff}.one{line-height:7rem;color:red}', + '.two{color:#fff}.one{height:7rem;line-height:7rem;color:red}' + ], + 'with two intermediate, non-overriding selectors': [ + '.one{color:red;margin:0}.two{color:#fff}.one{font-size:12px}', + '.one{color:red;margin:0;font-size:12px}.two{color:#fff}' + ], + 'with two intermediate, overriding more specific selectors': [ + '.one{color:red;margin:0}.two{font:12px serif}.one{font-size:12px}', + '.two{font:12px serif}.one{color:red;margin:0;font-size:12px}' + ], + 'with granular selectors from the same shorthand': [ + '.one{color:red;margin:0}.two{font-weight:700}.one{font-size:12px}', + '.one{color:red;margin:0;font-size:12px}.two{font-weight:700}' + ], + 'with three intermediate, non-overriding selectors': [ + '.one{color:red;margin:0}.two{color:#fff}.one{font-size:12px}.three{color:#000}.one{padding:0}', + '.one{color:red;margin:0;font-size:12px;padding:0}.two{color:#fff}.three{color:#000}' + ], + 'successive selectors': [ + 'footer,header{top:1.25em;bottom:1.25em}header{top:2.5em}footer{bottom:2.5em}', + 'footer,header{top:1.25em;bottom:1.25em}header{top:2.5em}footer{bottom:2.5em}' + ], + 'over a @media block': [ + '.one{color:red;margin:0}@media{.two{font-weight:700}}.one{font-size:12px}', + '.one{color:red;margin:0;font-size:12px}@media{.two{font-weight:700}}' + ] + }) + ) + .addBatch( + optimizerContext('advanced on and aggressive merging off', { + 'non-adjacent with multi selectors': [ + 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}', + '.one,a,p{color:red}a{padding:10px;margin:0}a,p{padding:0}' + ] + }, { aggressiveMerging: false }) + ) + .addBatch( + optimizerContext('advanced off', { + 'non-adjacent': [ + 'a{color:red;display:block}.one{font-size:12px}a{color:#fff;margin:2px}', + 'a{color:red;display:block}.one{font-size:12px}a{color:#fff;margin:2px}' + ] + }, { advanced: false }) + ) + .export(module); -- 2.34.1