Repository: Polymer/vulcanize
Pull request #166 (2015-04-24 22:05:41)

finalize comment stripping.

azakus: LGTM after squashing

Patch:
diff --git a/README.md b/README.md
index 9c123dd..6034d35 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,7 @@ This will install `vulcanize` to `/usr/local/bin/vulcanize`.
 - `--implicit-strip`: Like specifying --strip-excludes for all the transitive dependencies of imports specified with `--exclude`.
 - `--inline-scripts`: Inline external scripts.
 - `--inline-css`: Inline external stylesheets.
+- `--strip-comments`: Strips all HTML comments not containing an @license from the document.
 
 ## Usage
 The command
diff --git a/bin/vulcanize b/bin/vulcanize
index 2263585..d2fed33 100755
--- a/bin/vulcanize
+++ b/bin/vulcanize
@@ -30,6 +30,7 @@ var help = [
   '  --exclude <path>: exclude a subpath from root. Use multiple times to exclude multiple paths. Tags to excluded paths are kept.',
   '  --strip-exclude: Exclude a subpath and strip the link that includes it.',
   '  --implicit-strip: Equivalent to setting --strip-excludes for the transitive dependencies of imports specified in --exclude',
+  '  --strip-comments: Strips all HTML comments not containing an @license from the document',
   'Examples:',
   '  The command',
   '',
@@ -71,6 +72,7 @@ var args = nopt(
     abspath: require('path'),
     exclude: [String, Array],
     'strip-exclude': [String, Array],
+    'strip-comments': Boolean,
     'implicit-strip': Boolean,
     'inline-scripts': Boolean,
     'inline-css': Boolean
@@ -120,6 +122,7 @@ function stringToRegExp(str) {
 
 args.excludes = args.exclude || [];
 args.stripExcludes = args['strip-exclude'] || [];
+args.stripComments = args['strip-comments'];
 args.implicitStrip = args['implicit-strip'];
 args.inlineScripts = args['inline-scripts'];
 args.inlineCss = args['inline-css'];
diff --git a/lib/comment-map.js b/lib/comment-map.js
new file mode 100644
index 0000000..07b4e9a
--- /dev/null
+++ b/lib/comment-map.js
@@ -0,0 +1,40 @@
+/**
+ * @license
+ * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+ * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+ * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+ * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+ * Code distributed by Google as part of the polymer project is also
+ * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+ */
+function CommentMap() {
+  this.commentMap = Object.create(null);
+}
+
+CommentMap.prototype = {
+  get: function(comment) {
+    var c = this.normalize(comment);
+    return this.commentMap[c];
+  },
+  set: function(comment, value) {
+    var c = this.normalize(comment);
+    this.commentMap[c] = value;
+  },
+  keys: function() {
+    return Object.keys(this.commentMap);
+  },
+  normalize: function (comment) {
+    var c = comment;
+    // remove leading slashes
+    c = c.replace(/^\/*/, '');
+    // remove leading stars
+    c = c.replace(/^\s*[*]*/gm, '');
+    // remove trailing stars and slash
+    c = c.replace(/[*]*\s*\/?$/, '');
+    // remove all whitespace
+    c = c.replace(/\s/g, '');
+    return c;
+  }
+};
+
+module.exports = CommentMap;
\ No newline at end of file
diff --git a/lib/matchers.js b/lib/matchers.js
index 7ffcb18..4cfc1df 100644
--- a/lib/matchers.js
+++ b/lib/matchers.js
@@ -78,14 +78,4 @@ module.exports = {
   POLY_CSS_LINK: polymerExternalStyle,
   JS_SRC: p.AND(p.hasAttr('src'), jsMatcher),
   JS_INLINE: p.AND(p.NOT(p.hasAttr('src')), jsMatcher),
-  commentOrEmptyText: function(node) {
-    if (node.nodeName === '#text') {
-      return !/\S/.test(node.value);
-    }
-    if (node.nodeName === '#comment') {
-      return true;
-    }
-    return false;
-  }
-
 };
diff --git a/lib/pathresolver.js b/lib/pathresolver.js
index 470a10f..0c70ec4 100644
--- a/lib/pathresolver.js
+++ b/lib/pathresolver.js
@@ -38,7 +38,7 @@ function resolvePaths(importDoc, importUrl, mainDocUrl) {
           relUrl = rewriteURL(importUrl, mainDocUrl, attrValue);
         } else {
           relUrl = rewriteRelPath(importUrl, mainDocUrl, attrValue);
-          if (attr === 'assetpath') {
+          if (attr === 'assetpath' && relUrl.slice(-1) != '/') {
             relUrl += '/';
           }
         }
diff --git a/lib/vulcan.js b/lib/vulcan.js
index 1692146..7a848a0 100644
--- a/lib/vulcan.js
+++ b/lib/vulcan.js
@@ -14,6 +14,7 @@
 var path = require('path');
 var hyd = require('hydrolysis');
 var dom5 = require('dom5');
+var CommentMap = require('./comment-map');
 var constants = require('./constants');
 var matchers = require('./matchers');
 var pathResolver = require('./pathresolver');
@@ -126,6 +127,18 @@ function flatten(tree, bodyFragment) {
       }
     }
   }
+  // Deduplicate comments
+  var comments = new CommentMap();
+  dom5.nodeWalkAll(doc, dom5.isCommentNode).forEach(function(comment) {
+    comments.set(comment.data, comment);
+    dom5.remove(comment);
+  });
+  comments.keys().forEach(function (commentData) {
+    if (Options.stripComments && commentData.indexOf("@license") == -1) {
+      return;
+    }
+    prepend(head, comments.get(commentData));
+  });
   return doc;
 }
 


Test patch:
diff --git a/test/html/imports/simple-import.html b/test/html/imports/simple-import.html
index d122b8e..e0480e3 100644
--- a/test/html/imports/simple-import.html
+++ b/test/html/imports/simple-import.html
@@ -8,6 +8,9 @@
     subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 -->
 <dom-module id="my-element">
+<!--
+    This comment exists to be stripped.
+-->
   <link rel="import" type="css" href="simple-style.css">
   <template>
   <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 630 630">
diff --git a/test/test.js b/test/test.js
index 72efec4..531056f 100644
--- a/test/test.js
+++ b/test/test.js
@@ -436,6 +436,22 @@ suite('Vulcan', function() {
       };
       process(inputPath, callback, options);
     });
+
+    test('Excluded comments are removed', function(done) {
+      var options = {
+        stripComments: true
+      };
+      var callback = function(err, doc) {
+        if (err) {
+          return done(err);
+        }
+        var comments = dom5.nodeWalkAll(doc, dom5.isCommentNode);
+        assert.equal(comments.length, 1);
+        done();
+      };
+      console.log(inputPath);
+      process(inputPath, callback, options);
+    });
   });
 
   suite('Inline Scripts', function() {