Extracts rebuilding tokens into Stringifier class.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Sun, 2 Nov 2014 16:20:53 +0000 (16:20 +0000)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Mon, 8 Dec 2014 09:39:14 +0000 (09:39 +0000)
lib/clean.js
lib/selectors/optimizer.js
lib/selectors/stringifier.js [new file with mode: 0644]
test/selectors/optimizer-test.js

index f3f4b93..b716ecb 100644 (file)
@@ -8,6 +8,7 @@
 var ImportInliner = require('./imports/inliner');
 var UrlRebase = require('./images/url-rebase');
 var SelectorsOptimizer = require('./selectors/optimizer');
+var Stringifier = require('./selectors/stringifier');
 
 var CommentsProcessor = require('./text/comments-processor');
 var ExpressionsProcessor = require('./text/expressions-processor');
@@ -120,11 +121,10 @@ function minify(data) {
   var urlRebase = new UrlRebase(options, context);
   var selectorsOptimizer = new SelectorsOptimizer(options, context);
 
-  var run = function (processor, action, enabled) {
-    if (enabled === false)
-      return;
-
-    data = processor[action](data);
+  var run = function (processor, action) {
+    data = typeof processor == 'function' ?
+      processor(data) :
+      processor[action](data);
   };
 
   if (options.benchmark)
@@ -134,12 +134,18 @@ function minify(data) {
   run(expressionsProcessor, 'escape');
   run(urlsProcessor, 'escape');
   run(freeTextProcessor, 'escape');
-  run(selectorsOptimizer, 'process');
-  run(freeTextProcessor, 'restore');
-  run(urlsProcessor, 'restore');
-  run(urlRebase, 'process', options.rebase);
-  run(expressionsProcessor, 'restore');
-  run(commentsProcessor, 'restore');
+
+  run(function() {
+    var stringifier = new Stringifier(options.keepBreaks, function (data) {
+      data = freeTextProcessor.restore(data);
+      data = urlsProcessor.restore(data);
+      data = options.rebase ? urlRebase.process(data) : data;
+      data = expressionsProcessor.restore(data);
+      return commentsProcessor.restore(data);
+    });
+
+    return selectorsOptimizer.process(data, stringifier);
+  });
 
   return data;
 }
index 98d5e0a..3f6abf4 100644 (file)
@@ -2,64 +2,19 @@ var Tokenizer = require('./tokenizer');
 var SimpleOptimizer = require('./optimizers/simple');
 var AdvancedOptimizer = require('./optimizers/advanced');
 
-var lineBreak = require('os').EOL;
-
 function SelectorsOptimizer(options, context) {
   this.options = options || {};
   this.context = context || {};
 }
 
-function valueRebuilder(list, separator) {
-  var merged = '';
-
-  for (var i = 0, l = list.length; i < l; i++)
-    merged += list[i].value + (i < l - 1 ? separator : '');
-
-  return merged;
-}
-
-function rebuild(tokens, keepBreaks, isFlatBlock) {
-  var joinCharacter = isFlatBlock ? ';' : (keepBreaks ? lineBreak : '');
-  var parts = [];
-  var body;
-  var selector;
-
-  for (var i = 0, l = tokens.length; i < l; i++) {
-    var token = tokens[i];
-
-    if (token.kind === 'text' || token.kind == 'at-rule') {
-      parts.push(token.value);
-      continue;
-    }
-
-    // FIXME: broken due to joining/splitting
-    if (token.body && (token.body.length === 0 || (token.body.length == 1 && token.body[0].value === '')))
-      continue;
-
-    if (token.kind == 'block') {
-      body = token.isFlatBlock ?
-        valueRebuilder(token.body, ';') :
-        rebuild(token.body, keepBreaks, token.isFlatBlock);
-      if (body.length > 0)
-        parts.push(token.value + '{' + body + '}');
-    } else {
-      selector = valueRebuilder(token.value, ',');
-      body = valueRebuilder(token.body, ';');
-      parts.push(selector + '{' + body + '}');
-    }
-  }
-
-  return parts.join(joinCharacter);
-}
-
-SelectorsOptimizer.prototype.process = function (data) {
+SelectorsOptimizer.prototype.process = function (data, stringifier) {
   var tokens = new Tokenizer(this.context, this.options.advanced).toTokens(data);
 
   new SimpleOptimizer(this.options).optimize(tokens);
   if (this.options.advanced)
     new AdvancedOptimizer(this.options, this.context).optimize(tokens);
 
-  return rebuild(tokens, this.options.keepBreaks, false).trim();
+  return stringifier.toString(tokens);
 };
 
 module.exports = SelectorsOptimizer;
diff --git a/lib/selectors/stringifier.js b/lib/selectors/stringifier.js
new file mode 100644 (file)
index 0000000..c89f50a
--- /dev/null
@@ -0,0 +1,56 @@
+var lineBreak = require('os').EOL;
+
+function Stringifier(keepBreaks, restoreCallback) {
+  this.keepBreaks = keepBreaks;
+  this.restoreCallback = restoreCallback;
+}
+
+function valueRebuilder(list, separator) {
+  var merged = '';
+
+  for (var i = 0, l = list.length; i < l; i++)
+    merged += list[i].value + (i < l - 1 ? separator : '');
+
+  return merged;
+}
+
+function rebuild(tokens, keepBreaks, isFlatBlock) {
+  var joinCharacter = isFlatBlock ? ';' : (keepBreaks ? lineBreak : '');
+  var parts = [];
+  var body;
+  var selector;
+
+  for (var i = 0, l = tokens.length; i < l; i++) {
+    var token = tokens[i];
+
+    if (token.kind === 'text' || token.kind == 'at-rule') {
+      parts.push(token.value);
+      continue;
+    }
+
+    // FIXME: broken due to joining/splitting
+    if (token.body && (token.body.length === 0 || (token.body.length == 1 && token.body[0].value === '')))
+      continue;
+
+    if (token.kind == 'block') {
+      body = token.isFlatBlock ?
+        valueRebuilder(token.body, ';') :
+        rebuild(token.body, keepBreaks, token.isFlatBlock);
+      if (body.length > 0)
+        parts.push(token.value + '{' + body + '}');
+    } else {
+      selector = valueRebuilder(token.value, ',');
+      body = valueRebuilder(token.body, ';');
+      parts.push(selector + '{' + body + '}');
+    }
+  }
+
+  return parts.join(joinCharacter);
+}
+
+Stringifier.prototype.toString = function (tokens) {
+  var rebuilt = rebuild(tokens, this.keepBreaks, false);
+  return this.restoreCallback(rebuilt).trim();
+};
+
+module.exports = Stringifier;
index 1f5bf50..d316038 100644 (file)
@@ -1,16 +1,19 @@
 var vows = require('vows');
 var assert = require('assert');
 var SelectorsOptimizer = require('../../lib/selectors/optimizer');
+var Stringifier = require('../../lib/selectors/stringifier');
 var Compatibility = require('../../lib/utils/compatibility');
 
 function optimizerContext(group, specs, options) {
+  var stringifier = new Stringifier(false, function (data) { return data; });
+
   var context = {};
   options = options || {};
   options.compatibility = new Compatibility(options.compatibility).toOptions();
 
   function optimized(target) {
     return function (source) {
-      assert.equal(new SelectorsOptimizer(options).process(source), target);
+      assert.equal(new SelectorsOptimizer(options).process(source, stringifier), target);
     };
   }