preserve input `options` (#910)
authorAlex Lam S.L <alexlamsl@gmail.com>
Mon, 16 Apr 2018 14:18:20 +0000 (22:18 +0800)
committeralexlamsl <alexlamsl@gmail.com>
Mon, 16 Apr 2018 18:02:22 +0000 (02:02 +0800)
src/htmlminifier.js

index 120e62b..c00958e 100644 (file)
@@ -613,113 +613,107 @@ function identity(value) {
   return value;
 }
 
-function processOptions(options) {
-  ['html5', 'includeAutoGeneratedTags'].forEach(function(key) {
-    if (!(key in options)) {
-      options[key] = true;
-    }
-  });
-
-  if (typeof options.log !== 'function') {
-    options.log = identity;
-  }
-
-  if (!options.canCollapseWhitespace) {
-    options.canCollapseWhitespace = canCollapseWhitespace;
-  }
-  if (!options.canTrimWhitespace) {
-    options.canTrimWhitespace = canTrimWhitespace;
-  }
-
-  if (!('ignoreCustomComments' in options)) {
-    options.ignoreCustomComments = [/^!/];
-  }
-
-  if (!('ignoreCustomFragments' in options)) {
-    options.ignoreCustomFragments = [
+function processOptions(values) {
+  var options = {
+    canCollapseWhitespace: canCollapseWhitespace,
+    canTrimWhitespace: canTrimWhitespace,
+    html5: true,
+    ignoreCustomComments: [/^!/],
+    ignoreCustomFragments: [
       /<%[\s\S]*?%>/,
       /<\?[\s\S]*?\?>/
-    ];
-  }
-
-  if (!options.minifyURLs) {
-    options.minifyURLs = identity;
-  }
-  if (typeof options.minifyURLs !== 'function') {
-    var minifyURLs = options.minifyURLs;
-    if (typeof minifyURLs === 'string') {
-      minifyURLs = { site: minifyURLs };
-    }
-    else if (typeof minifyURLs !== 'object') {
-      minifyURLs = {};
-    }
-    options.minifyURLs = function(text) {
-      try {
-        return RelateUrl.relate(text, minifyURLs);
-      }
-      catch (err) {
-        options.log(err);
-        return text;
+    ],
+    includeAutoGeneratedTags: true,
+    log: identity,
+    minifyCSS: identity,
+    minifyJS: identity,
+    minifyURLs: identity
+  };
+  Object.keys(values).forEach(function(key) {
+    var value = values[key];
+    if (key === 'log') {
+      if (typeof value === 'function') {
+        options.log = value;
       }
-    };
-  }
-
-  if (!options.minifyJS) {
-    options.minifyJS = identity;
-  }
-  if (typeof options.minifyJS !== 'function') {
-    var minifyJS = options.minifyJS;
-    if (typeof minifyJS !== 'object') {
-      minifyJS = {};
     }
-    (minifyJS.parse || (minifyJS.parse = {})).bare_returns = false;
-    options.minifyJS = function(text, inline) {
-      var start = text.match(/^\s*<!--.*/);
-      var code = start ? text.slice(start[0].length).replace(/\n\s*-->\s*$/, '') : text;
-      minifyJS.parse.bare_returns = inline;
-      var result = UglifyJS.minify(code, minifyJS);
-      if (result.error) {
-        options.log(result.error);
-        return text;
+    else if (key === 'minifyCSS' && typeof value !== 'function') {
+      if (!value) {
+        return;
       }
-      return result.code.replace(/;$/, '');
-    };
-  }
-
-  if (!options.minifyCSS) {
-    options.minifyCSS = identity;
-  }
-  if (typeof options.minifyCSS !== 'function') {
-    var minifyCSS = options.minifyCSS;
-    if (typeof minifyCSS !== 'object') {
-      minifyCSS = {};
-    }
-    options.minifyCSS = function(text, type) {
-      text = text.replace(/(url\s*\(\s*)("|'|)(.*?)\2(\s*\))/ig, function(match, prefix, quote, url, suffix) {
-        return prefix + quote + options.minifyURLs(url) + quote + suffix;
-      });
-      try {
-        if (type === 'inline') {
-          text = wrapInlineCSS(text);
-        }
-        else if (type === 'media') {
-          text = wrapMediaQuery(text);
+      if (typeof value !== 'object') {
+        value = {};
+      }
+      options.minifyCSS = function(text, type) {
+        text = text.replace(/(url\s*\(\s*)("|'|)(.*?)\2(\s*\))/ig, function(match, prefix, quote, url, suffix) {
+          return prefix + quote + options.minifyURLs(url) + quote + suffix;
+        });
+        try {
+          if (type === 'inline') {
+            text = wrapInlineCSS(text);
+          }
+          else if (type === 'media') {
+            text = wrapMediaQuery(text);
+          }
+          text = new CleanCSS(value).minify(text).styles;
+          if (type === 'inline') {
+            text = unwrapInlineCSS(text);
+          }
+          else if (type === 'media') {
+            text = unwrapMediaQuery(text);
+          }
+          return text;
         }
-        text = new CleanCSS(minifyCSS).minify(text).styles;
-        if (type === 'inline') {
-          text = unwrapInlineCSS(text);
+        catch (err) {
+          options.log(err);
+          return text;
         }
-        else if (type === 'media') {
-          text = unwrapMediaQuery(text);
+      };
+    }
+    else if (key === 'minifyJS' && typeof value !== 'function') {
+      if (!value) {
+        return;
+      }
+      if (typeof value !== 'object') {
+        value = {};
+      }
+      (value.parse || (value.parse = {})).bare_returns = false;
+      options.minifyJS = function(text, inline) {
+        var start = text.match(/^\s*<!--.*/);
+        var code = start ? text.slice(start[0].length).replace(/\n\s*-->\s*$/, '') : text;
+        value.parse.bare_returns = inline;
+        var result = UglifyJS.minify(code, value);
+        if (result.error) {
+          options.log(result.error);
+          return text;
         }
-        return text;
+        return result.code.replace(/;$/, '');
+      };
+    }
+    else if (key === 'minifyURLs' && typeof value !== 'function') {
+      if (!value) {
+        return;
       }
-      catch (err) {
-        options.log(err);
-        return text;
+      if (typeof value === 'string') {
+        value = { site: value };
       }
-    };
-  }
+      else if (typeof value !== 'object') {
+        value = {};
+      }
+      options.minifyURLs = function(text) {
+        try {
+          return RelateUrl.relate(text, value);
+        }
+        catch (err) {
+          options.log(err);
+          return text;
+        }
+      };
+    }
+    else {
+      options[key] = value;
+    }
+  });
+  return options;
 }
 
 function uniqueId(value) {
@@ -784,7 +778,7 @@ function createSortFns(value, options, uidIgnore, uidAttr) {
   }
 
   var log = options.log;
-  options.log = null;
+  options.log = identity;
   options.sortAttributes = false;
   options.sortClassName = false;
   scan(minify(value, options));
@@ -817,9 +811,6 @@ function createSortFns(value, options, uidIgnore, uidAttr) {
 }
 
 function minify(value, options, partialMarkup) {
-  options = options || {};
-  var optionsStack = [];
-  processOptions(options);
   if (options.collapseWhitespace) {
     value = collapseWhitespace(value, options, true, true);
   }
@@ -834,7 +825,6 @@ function minify(value, options, partialMarkup) {
       stackNoCollapseWhitespace = [],
       optionalStartTag = '',
       optionalEndTag = '',
-      t = Date.now(),
       ignoredMarkupChunks = [],
       ignoredCustomMarkupChunks = [],
       uidIgnore,
@@ -850,22 +840,25 @@ function minify(value, options, partialMarkup) {
       uidIgnore = uniqueId(value);
       var pattern = new RegExp('^' + uidIgnore + '([0-9]+)$');
       if (options.ignoreCustomComments) {
-        options.ignoreCustomComments.push(pattern);
+        options.ignoreCustomComments = options.ignoreCustomComments.slice();
       }
       else {
-        options.ignoreCustomComments = [pattern];
+        options.ignoreCustomComments = [];
       }
+      options.ignoreCustomComments.push(pattern);
     }
     var token = '<!--' + uidIgnore + ignoredMarkupChunks.length + '-->';
     ignoredMarkupChunks.push(group1);
     return token;
   });
 
-  function escapeFragments(text) {
-    return text.replace(uidPattern, function(match, prefix, index) {
-      var chunks = ignoredCustomMarkupChunks[+index];
-      return chunks[1] + uidAttr + index + chunks[2];
-    });
+  function escapeFragments(fn) {
+    return function(text, type) {
+      return fn(text.replace(uidPattern, function(match, prefix, index) {
+        var chunks = ignoredCustomMarkupChunks[+index];
+        return chunks[1] + uidAttr + index + chunks[2];
+      }), type);
+    };
   }
 
   var customFragments = options.ignoreCustomFragments.map(function(re) {
@@ -878,17 +871,11 @@ function minify(value, options, partialMarkup) {
       if (!uidAttr) {
         uidAttr = uniqueId(value);
         uidPattern = new RegExp('(\\s*)' + uidAttr + '([0-9]+)(\\s*)', 'g');
-        var minifyCSS = options.minifyCSS;
-        if (minifyCSS) {
-          options.minifyCSS = function(text, type) {
-            return minifyCSS(escapeFragments(text), type);
-          };
+        if (options.minifyCSS) {
+          options.minifyCSS = escapeFragments(options.minifyCSS);
         }
-        var minifyJS = options.minifyJS;
-        if (minifyJS) {
-          options.minifyJS = function(text, inline) {
-            return minifyJS(escapeFragments(text), inline);
-          };
+        if (options.minifyJS) {
+          options.minifyJS = escapeFragments(options.minifyJS);
         }
       }
       var token = uidAttr + ignoredCustomMarkupChunks.length;
@@ -962,14 +949,9 @@ function minify(value, options, partialMarkup) {
       var lowerTag = tag.toLowerCase();
 
       if (lowerTag === 'svg') {
-        optionsStack.push(options);
-        var nextOptions = {};
-        for (var key in options) {
-          nextOptions[key] = options[key];
-        }
-        nextOptions.keepClosingSlash = true;
-        nextOptions.caseSensitive = true;
-        options = nextOptions;
+        options = Object.create(options);
+        options.keepClosingSlash = true;
+        options.caseSensitive = true;
       }
 
       tag = options.caseSensitive ? tag : lowerTag;
@@ -1055,7 +1037,7 @@ function minify(value, options, partialMarkup) {
     end: function(tag, attrs, autoGenerated) {
       var lowerTag = tag.toLowerCase();
       if (lowerTag === 'svg') {
-        options = optionsStack.pop();
+        options = Object.getPrototypeOf(options);
       }
       tag = options.caseSensitive ? tag : lowerTag;
 
@@ -1282,7 +1264,6 @@ function minify(value, options, partialMarkup) {
     });
   }
 
-  options.log('minified in: ' + (Date.now() - t) + 'ms');
   return str;
 }
 
@@ -1314,5 +1295,9 @@ function joinResultSegments(results, options) {
 }
 
 exports.minify = function(value, options) {
-  return minify(value, options);
+  var start = Date.now();
+  options = processOptions(options || {});
+  var result = minify(value, options);
+  options.log('minified in: ' + (Date.now() - start) + 'ms');
+  return result;
 };