var canReorder = require('./reorderable').canReorder;
+var canReorderSingle = require('./reorderable').canReorderSingle;
var extractProperties = require('./extract-properties');
+var rulesOverlap = require('./rules-overlap');
var serializeRules = require('../writer/one-time').rules;
var Token = require('../tokenizer/token');
-function mergeMediaQueries(tokens) {
+function mergeMediaQueries(tokens, context) {
+ var semanticMerging = context.options.semanticMerging;
var candidates = {};
var reduced = [];
var traversedProperties = extractProperties(tokens[from]);
from += delta;
+ if (semanticMerging && allSameRulePropertiesCanBeReordered(movedProperties, traversedProperties)) {
+ continue;
+ }
+
if (!canReorder(movedProperties, traversedProperties))
continue directionLoop;
}
return reduced;
}
+function allSameRulePropertiesCanBeReordered(movedProperties, traversedProperties) {
+ var movedProperty;
+ var movedRule;
+ var traversedProperty;
+ var traversedRule;
+ var i, l;
+ var j, m;
+
+ for (i = 0, l = movedProperties.length; i < l; i++) {
+ movedProperty = movedProperties[i];
+ movedRule = movedProperty[5];
+
+ for (j = 0, m = traversedProperties.length; j < m; j++) {
+ traversedProperty = traversedProperties[i];
+ traversedRule = traversedProperty[5];
+
+ if (rulesOverlap(movedRule, traversedRule, true) && !canReorderSingle(movedProperty, traversedProperty)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
module.exports = mergeMediaQueries;
--- /dev/null
+var MODIFIER_PATTERN = /\-\-.+$/;
+
+function rulesOverlap(rule1, rule2, bemMode) {
+ var scope1;
+ var scope2;
+ var i, l;
+ var j, m;
+
+ for (i = 0, l = rule1.length; i < l; i++) {
+ scope1 = rule1[i][1];
+
+ for (j = 0, m = rule2.length; j < m; j++) {
+ scope2 = rule2[j][1];
+
+ if (scope1 == scope2) {
+ return true;
+ }
+
+ if (bemMode && withoutModifiers(scope1) == withoutModifiers(scope2)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+function withoutModifiers(scope) {
+ return scope.replace(MODIFIER_PATTERN, '');
+}
+
+module.exports = rulesOverlap;
]
})
)
+ .addBatch(
+ optimizerContext('semantic merging mode', {
+ 'moves over an otherwise blocking property': [
+ '@media (max-width:1px){.a{margin:1px}}.b{margin:2px}@media (max-width:1px){.c{margin:3px}}',
+ '.b{margin:2px}@media (max-width:1px){.a{margin:1px}.c{margin:3px}}'
+ ],
+ 'moves over an otherwise blocking longhand property': [
+ '@media (max-width:1px){.a{margin:1px}}.a{margin-bottom:2px}@media (max-width:1px){.a{margin:3px}}',
+ '@media (max-width:1px){.a{margin:1px}}.a{margin-bottom:2px}@media (max-width:1px){.a{margin:3px}}'
+ ],
+ 'does not move if separating selector redefines a property': [
+ '@media (max-width:1px){.a{margin:1px}}.a{margin:2px}@media (max-width:1px){.a{margin:3px}}',
+ '@media (max-width:1px){.a{margin:1px}}.a{margin:2px}@media (max-width:1px){.a{margin:3px}}'
+ ],
+ 'does not move over blocking BEM block rules': [
+ '@media (max-width:1px){.block{margin:1px}}.block--modifier1{margin:2px}@media (max-width:1px){.block--modifier2{margin:3px}}',
+ '@media (max-width:1px){.block{margin:1px}}.block--modifier1{margin:2px}@media (max-width:1px){.block--modifier2{margin:3px}}'
+ ],
+ 'does not move over blocking BEM element rules': [
+ '@media (max-width:1px){.block__element{margin:1px}}.block__element--modifier1{margin:2px}@media (max-width:1px){.block__element--modifier2{margin:3px}}',
+ '@media (max-width:1px){.block__element{margin:1px}}.block__element--modifier1{margin:2px}@media (max-width:1px){.block__element--modifier2{margin:3px}}'
+ ],
+ 'moves over non-blocking BEM rules': [
+ '@media (max-width:1px){.block{margin:1px}}.block__element{margin:2px}@media (max-width:1px){.block--modifier{margin:3px}}',
+ '.block__element{margin:2px}@media (max-width:1px){.block{margin:1px}.block--modifier{margin:3px}}'
+ ]
+ }, { semanticMerging: true })
+ )
.addBatch(
optimizerContext('advanced off', {
'keeps content same': [
--- /dev/null
+var assert = require('assert');
+
+var vows = require('vows');
+
+var rulesOverlap = require('../../lib/optimizer/rules-overlap');
+
+vows.describe(rulesOverlap)
+ .addBatch({
+ 'single non-overlapping scopes': {
+ 'topic': function () {
+ return rulesOverlap(
+ [['rule-scope', '.one']],
+ [['rule-scope', '.two']]
+ );
+ },
+ 'do not overlap': function (result) {
+ assert.isFalse(result);
+ }
+ },
+ 'single overlapping scopes': {
+ 'topic': function () {
+ return rulesOverlap(
+ [['rule-scope', '.one']],
+ [['rule-scope', '.one']]
+ );
+ },
+ 'do overlap': function (result) {
+ assert.isTrue(result);
+ }
+ },
+ 'multiple non-overlapping scopes': {
+ 'topic': function () {
+ return rulesOverlap(
+ [['rule-scope', '.one'], ['rule-scope', '.two .three']],
+ [['rule-scope', '.two'], ['rule-scope', '.four']]
+ );
+ },
+ 'do not overlap': function (result) {
+ assert.isFalse(result);
+ }
+ },
+ 'multiple overlapping scopes': {
+ 'topic': function () {
+ return rulesOverlap(
+ [['rule-scope', '.one'], ['rule-scope', '.four']],
+ [['rule-scope', '.one'], ['rule-scope', '.four']]
+ );
+ },
+ 'do overlap': function (result) {
+ assert.isTrue(result);
+ }
+ }
+ })
+ .addBatch({
+ 'single non-overlapping BEM scopes in BEM mode': {
+ 'topic': function () {
+ return rulesOverlap(
+ [['rule-scope', '.one']],
+ [['rule-scope', '.two--modifier']],
+ true
+ );
+ },
+ 'do overlap': function (result) {
+ assert.isFalse(result);
+ }
+ },
+ 'single overlapping BEM scopes in BEM mode': {
+ 'topic': function () {
+ return rulesOverlap(
+ [['rule-scope', '.one']],
+ [['rule-scope', '.one--modifier']],
+ true
+ );
+ },
+ 'do overlap': function (result) {
+ assert.isTrue(result);
+ }
+ },
+ 'single overlapping BEM scopes with modifiers in BEM mode': {
+ 'topic': function () {
+ return rulesOverlap(
+ [['rule-scope', '.one--modifier1']],
+ [['rule-scope', '.one--modifier2']],
+ true
+ );
+ },
+ 'do overlap': function (result) {
+ assert.isTrue(result);
+ }
+ },
+ })
+ .export(module);