Replaces basic escaping of special data with one based on hashes.
authorGoalSmashers <jakub@goalsmashers.com>
Fri, 27 Sep 2013 10:50:34 +0000 (12:50 +0200)
committerGoalSmashers <jakub@goalsmashers.com>
Fri, 27 Sep 2013 12:12:15 +0000 (14:12 +0200)
* Adds EscapeStore helper class to aid escaping and restoring.
* Necessary for selector- and property-level optimizations.

History.md
lib/text/comments.js
lib/text/escape-store.js [new file with mode: 0644]
lib/text/expressions.js
lib/text/free.js
lib/text/urls.js

index 6aef865..58e281e 100644 (file)
@@ -1,3 +1,8 @@
+2.0.0 / 2013-xx-xx (UNRELEASED)
+==================
+
+* Adds simplified and more advanced text escaping / restoring via EscapeStore class.
+
 1.1.1 / 2013-09-07
 ==================
 
index d5543e1..a1b6e43 100644 (file)
@@ -1,5 +1,7 @@
+var EscapeStore = require('./escape-store');
+
 module.exports = function Comments(keepSpecialComments, keepBreaks, lineBreak) {
-  var comments = [];
+  var comments = new EscapeStore('CSSCOMMENT');
 
   return {
     // Strip special comments (/*! ... */) by replacing them by __CSSCOMMENT__ marker
@@ -20,8 +22,9 @@ module.exports = function Comments(keepSpecialComments, keepBreaks, lineBreak) {
         tempData.push(data.substring(cursor, nextStart));
         if (data[nextStart + 2] == '!') {
           // in case of special comments, replace them with a placeholder
-          comments.push(data.substring(nextStart, nextEnd + 2));
-          tempData.push('__CSSCOMMENT__');
+          var comment = data.substring(nextStart, nextEnd + 2);
+          var placeholder = comments.store(comment);
+          tempData.push(placeholder);
         }
         cursor = nextEnd + 2;
       }
@@ -32,16 +35,18 @@ module.exports = function Comments(keepSpecialComments, keepBreaks, lineBreak) {
     },
 
     restore: function(data) {
-      var commentsCount = comments.length;
+      var restored = 0;
       var breakSuffix = keepBreaks ? lineBreak : '';
 
-      return data.replace(new RegExp('__CSSCOMMENT__(' + lineBreak + '| )?', 'g'), function() {
+      return data.replace(new RegExp(comments.placeholderPattern + '(' + lineBreak + '| )?', 'g'), function(match, placeholder) {
+        restored++;
+
         switch (keepSpecialComments) {
           case '*':
-            return comments.shift() + breakSuffix;
+            return comments.restore(placeholder) + breakSuffix;
           case 1:
-            return comments.length == commentsCount ?
-              comments.shift() + breakSuffix :
+            return restored == 1 ?
+              comments.restore(placeholder) + breakSuffix :
               '';
           case 0:
             return '';
diff --git a/lib/text/escape-store.js b/lib/text/escape-store.js
new file mode 100644 (file)
index 0000000..a4fded8
--- /dev/null
@@ -0,0 +1,30 @@
+module.exports = function EscapeStore(placeholderRoot) {
+  var placeholderToData = {};
+  var dataToPlaceholder = {};
+  var count = 0;
+  var nextPlaceholder = function() {
+    return '__' + placeholderRoot + (count++) + '__';
+  };
+  var pattern = '(__' + placeholderRoot + '\\d{1,}__)';
+
+  return {
+    placeholderPattern: pattern,
+
+    placeholderRegExp: new RegExp(pattern, 'g'),
+
+    store: function(data) {
+      var placeholder = dataToPlaceholder[data];
+      if (!placeholder) {
+        placeholder = nextPlaceholder();
+        placeholderToData[placeholder] = data;
+        dataToPlaceholder[data] = placeholder;
+      }
+
+      return placeholder;
+    },
+
+    restore: function(placeholder) {
+      return placeholderToData[placeholder];
+    }
+  };
+};
index 92575d0..0157148 100644 (file)
@@ -1,5 +1,7 @@
+var EscapeStore = require('./escape-store');
+
 module.exports = function Expressions() {
-  var expressions = [];
+  var expressions = new EscapeStore('EXPRESSION');
 
   var findEnd = function(data, start) {
     var end = start + 'expression'.length;
@@ -44,9 +46,10 @@ module.exports = function Expressions() {
 
         nextEnd = findEnd(data, nextStart);
 
+        var expression = data.substring(nextStart, nextEnd);
+        var placeholder = expressions.store(expression);
         tempData.push(data.substring(cursor, nextStart));
-        tempData.push('__EXPRESSION__');
-        expressions.push(data.substring(nextStart, nextEnd));
+        tempData.push(placeholder);
         cursor = nextEnd;
       }
 
@@ -56,9 +59,7 @@ module.exports = function Expressions() {
     },
 
     restore: function(data) {
-      return data.replace(/__EXPRESSION__/g, function() {
-        return expressions.shift();
-      });
+      return data.replace(expressions.placeholderRegExp, expressions.restore);
     }
   };
 };
index 973e326..dab22b1 100644 (file)
@@ -1,5 +1,7 @@
+var EscapeStore = require('./escape-store');
+
 module.exports = function Free() {
-  var texts = [];
+  var texts = new EscapeStore('CSSFREETEXT');
 
   return {
     // Strip content tags by replacing them by the __CSSFREETEXT__
@@ -39,9 +41,10 @@ module.exports = function Free() {
         if (nextStart == -1 || nextEnd == -1)
           break;
 
+        var text = data.substring(nextStart, nextEnd + 1);
+        var placeholder = texts.store(text);
         tempData.push(data.substring(cursor, nextStart));
-        tempData.push('__CSSFREETEXT__');
-        texts.push(data.substring(nextStart, nextEnd + 1));
+        tempData.push(placeholder);
         cursor = nextEnd + 1;
       }
 
@@ -51,9 +54,7 @@ module.exports = function Free() {
     },
 
     restore: function(data) {
-      return data.replace(/__CSSFREETEXT__/g, function() {
-        return texts.shift();
-      });
+      return data.replace(texts.placeholderRegExp, texts.restore);
     }
   };
 };
index 7e83ee6..669352a 100644 (file)
@@ -1,5 +1,7 @@
+var EscapeStore = require('./escape-store');
+
 module.exports = function Urls() {
-  var urls = [];
+  var urls = new EscapeStore('URL');
 
   return {
     // Strip urls by replacing them by the __URL__
@@ -18,9 +20,10 @@ module.exports = function Urls() {
 
         nextEnd = data.indexOf(')', nextStart);
 
+        var url = data.substring(nextStart, nextEnd + 1);
+        var placeholder = urls.store(url);
         tempData.push(data.substring(cursor, nextStart));
-        tempData.push('__URL__');
-        urls.push(data.substring(nextStart, nextEnd + 1));
+        tempData.push(placeholder);
         cursor = nextEnd + 1;
       }
 
@@ -30,9 +33,7 @@ module.exports = function Urls() {
     },
 
     restore: function(data) {
-      return data.replace(/__URL__/g, function() {
-        return urls.shift();
-      });
+      return data.replace(urls.placeholderRegExp, urls.restore);
     }
   };
 };