Extracts 'remove duplicates' optimization into a module.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Sun, 21 Jun 2015 10:40:18 +0000 (11:40 +0100)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Sun, 21 Jun 2015 10:40:18 +0000 (11:40 +0100)
lib/selectors/advanced.js
lib/selectors/remove-duplicates.js [new file with mode: 0644]
test/integration-test.js
test/selectors/advanced-test.js
test/selectors/remove-duplicates-test.js [new file with mode: 0644]

index b78d63b..0bde05b 100644 (file)
@@ -8,6 +8,8 @@ var stringifyAll = require('../stringifier/one-time').all;
 var stringifyBody = require('../stringifier/one-time').body;
 var stringifySelectors = require('../stringifier/one-time').selectors;
 
+var removeDuplicates = require('./remove-duplicates');
+
 function AdvancedOptimizer(options, context) {
   this.options = options;
   this.validator = context.validator;
@@ -25,43 +27,6 @@ AdvancedOptimizer.prototype.isSpecial = function (selector) {
   return this.options.compatibility.selectors.special.test(selector);
 };
 
-AdvancedOptimizer.prototype.removeDuplicates = function (tokens) {
-  var matched = {};
-  var moreThanOnce = [];
-  var id, token;
-  var body, bodies;
-
-  for (var i = 0, l = tokens.length; i < l; i++) {
-    token = tokens[i];
-    if (token[0] != 'selector')
-      continue;
-
-    id = stringifySelectors(token[1]);
-
-    if (matched[id] && matched[id].length == 1)
-      moreThanOnce.push(id);
-    else
-      matched[id] = matched[id] || [];
-
-    matched[id].push(i);
-  }
-
-  for (i = 0, l = moreThanOnce.length; i < l; i++) {
-    id = moreThanOnce[i];
-    bodies = [];
-
-    for (var j = matched[id].length - 1; j >= 0; j--) {
-      token = tokens[matched[id][j]];
-      body = stringifyBody(token[2]);
-
-      if (bodies.indexOf(body) > -1)
-        token[2] = [];
-      else
-        bodies.push(body);
-    }
-  }
-};
-
 AdvancedOptimizer.prototype.mergeAdjacent = function (tokens) {
   var lastToken = [null, [], []];
   var adjacentSpace = this.options.compatibility.selectors.adjacentSpace;
@@ -813,7 +778,7 @@ AdvancedOptimizer.prototype.optimize = function (tokens) {
 
     recursivelyOptimizeProperties(tokens, self.options, self.validator);
 
-    self.removeDuplicates(tokens);
+    removeDuplicates(tokens);
     self.mergeAdjacent(tokens);
     self.reduceNonAdjacent(tokens);
 
diff --git a/lib/selectors/remove-duplicates.js b/lib/selectors/remove-duplicates.js
new file mode 100644 (file)
index 0000000..3a2ce95
--- /dev/null
@@ -0,0 +1,41 @@
+var stringifyBody = require('../stringifier/one-time').body;
+var stringifySelectors = require('../stringifier/one-time').selectors;
+
+function removeDuplicates(tokens) {
+  var matched = {};
+  var moreThanOnce = [];
+  var id, token;
+  var body, bodies;
+
+  for (var i = 0, l = tokens.length; i < l; i++) {
+    token = tokens[i];
+    if (token[0] != 'selector')
+      continue;
+
+    id = stringifySelectors(token[1]);
+
+    if (matched[id] && matched[id].length == 1)
+      moreThanOnce.push(id);
+    else
+      matched[id] = matched[id] || [];
+
+    matched[id].push(i);
+  }
+
+  for (i = 0, l = moreThanOnce.length; i < l; i++) {
+    id = moreThanOnce[i];
+    bodies = [];
+
+    for (var j = matched[id].length - 1; j >= 0; j--) {
+      token = tokens[matched[id][j]];
+      body = stringifyBody(token[2]);
+
+      if (bodies.indexOf(body) > -1)
+        token[2] = [];
+      else
+        bodies.push(body);
+    }
+  }
+}
+
+module.exports = removeDuplicates;
index a8d95ae..9c9bc2a 100644 (file)
@@ -2146,38 +2146,6 @@ vows.describe('integration tests')
       ]
     })
   )
-  .addBatch(
-    optimizerContext('duplicate selectors in a scope', {
-      'of two successive selectors': [
-        'a{color:red}a{color:red}',
-        'a{color:red}'
-      ],
-      'of two successive selectors with different body': [
-        'a{color:red}a{display:block}',
-        'a{color:red;display:block}'
-      ],
-      'of many successive selectors': [
-        'a{color:red}a{color:red}a{color:red}a{color:red}',
-        'a{color:red}'
-      ],
-      'of two non-successive selectors': [
-        'a{color:red}p{color:#fff}a{color:red}',
-        'p{color:#fff}a{color:red}'
-      ],
-      'of many non-successive selectors': [
-        'div{width:100%}a{color:red}a{color:red}p{color:#fff}div{width:100%}ol{margin:0}p{color:#fff}',
-        'a{color:red}div{width:100%}ol{margin:0}p{color:#fff}'
-      ],
-      'with global and media scope': [
-        'a{color:red}@media screen{a{color:red}p{width:100px}a{color:red}}',
-        'a{color:red}@media screen{p{width:100px}a{color:red}}'
-      ],
-      'with two media scopes': [
-        '@media (min-width:100px){a{color:red}}@media screen{a{color:red}p{width:100px}a{color:red}}',
-        '@media (min-width:100px){a{color:red}}@media screen{p{width:100px}a{color:red}}'
-      ]
-    })
-  )
   .addBatch(
     optimizerContext('duplicate properties with aggressive merging disabled', {
       'of (yet) unmergeable properties': [
index c26463b..04152de 100644 (file)
@@ -209,14 +209,6 @@ vows.describe('advanced optimizer')
         'a{color:red;color:red}',
         'a{color:red}'
       ],
-      'duplicates - same context': [
-        'a{color:red}div{color:blue}a{color:red}',
-        'div{color:#00f}a{color:red}'
-      ],
-      'duplicates - different contexts': [
-        'a{color:red}div{color:blue}@media screen{a{color:red}}',
-        'a{color:red}div{color:#00f}@media screen{a{color:red}}'
-      ],
       'adjacent': [
         'a{color:red}a{display:block;width:100px}div{color:#fff}',
         'a{color:red;display:block;width:100px}div{color:#fff}'
@@ -257,14 +249,6 @@ vows.describe('advanced optimizer')
         'a{color:red;color:red}',
         'a{color:red;color:red}'
       ],
-      'duplicates - same context': [
-        'a{color:red}div{color:blue}a{color:red}',
-        'a{color:red}div{color:#00f}a{color:red}'
-      ],
-      'duplicates - different contexts': [
-        'a{color:red}div{color:blue}@media screen{a{color:red}}',
-        'a{color:red}div{color:#00f}@media screen{a{color:red}}'
-      ],
       'adjacent': [
         'a{color:red}a{display:block;width:100px}div{color:#fff}',
         'a{color:red}a{display:block;width:100px}div{color:#fff}'
diff --git a/test/selectors/remove-duplicates-test.js b/test/selectors/remove-duplicates-test.js
new file mode 100644 (file)
index 0000000..6886e9c
--- /dev/null
@@ -0,0 +1,57 @@
+var vows = require('vows');
+var optimizerContext = require('../test-helper').optimizerContext;
+
+vows.describe('remove duplicates')
+  .addBatch(
+    optimizerContext('advanced on', {
+      'same context': [
+        'a{color:red}div{color:blue}a{color:red}',
+        'div{color:#00f}a{color:red}'
+      ],
+      'different contexts': [
+        'a{color:red}div{color:blue}@media screen{a{color:red}}',
+        'a{color:red}div{color:#00f}@media screen{a{color:red}}'
+      ],
+      'of two successive selectors': [
+        'a{color:red}a{color:red}',
+        'a{color:red}'
+      ],
+      'of two successive selectors with different body': [
+        'a{color:red}a{display:block}',
+        'a{color:red;display:block}'
+      ],
+      'of many successive selectors': [
+        'a{color:red}a{color:red}a{color:red}a{color:red}',
+        'a{color:red}'
+      ],
+      'of two non-successive selectors': [
+        'a{color:red}p{color:#fff}a{color:red}',
+        'p{color:#fff}a{color:red}'
+      ],
+      'of many non-successive selectors': [
+        'div{width:100%}a{color:red}a{color:red}p{color:#fff}div{width:100%}ol{margin:0}p{color:#fff}',
+        'a{color:red}div{width:100%}ol{margin:0}p{color:#fff}'
+      ],
+      'with global and media scope': [
+        'a{color:red}@media screen{a{color:red}p{width:100px}a{color:red}}',
+        'a{color:red}@media screen{p{width:100px}a{color:red}}'
+      ],
+      'with two media scopes': [
+        '@media (min-width:100px){a{color:red}}@media screen{a{color:red}p{width:100px}a{color:red}}',
+        '@media (min-width:100px){a{color:red}}@media screen{p{width:100px}a{color:red}}'
+      ]
+    })
+  )
+  .addBatch(
+    optimizerContext('advanced off', {
+      'same context': [
+        'a{color:red}div{color:blue}a{color:red}',
+        'a{color:red}div{color:#00f}a{color:red}'
+      ],
+      'different contexts': [
+        'a{color:red}div{color:blue}@media screen{a{color:red}}',
+        'a{color:red}div{color:#00f}@media screen{a{color:red}}'
+      ],
+    }, { advanced: false })
+  )
+  .export(module);