Repository: Polymer/vulcanize
Pull request #334 (2016-04-08 22:48:26)

So much simpler
Move all imports and scripts to <body>, then replace inline


Patch:
diff --git a/.jshintignore b/.jshintignore
new file mode 100644
index 0000000..80a342d
--- /dev/null
+++ b/.jshintignore
@@ -0,0 +1,2 @@
+test/html/complicated/A.js
+test/html/complicated/C/C.js
diff --git a/lib/vulcan.js b/lib/vulcan.js
index c17cce0..4e2add3 100644
--- a/lib/vulcan.js
+++ b/lib/vulcan.js
@@ -153,26 +153,8 @@ Vulcan.prototype = {
     return Boolean(dom5.query(doc, matchers.polymerElement));
   },
 
-  replaceWith: function replaceWith(head, node, replacements) {
-    replacements.forEach(this.reparent(head));
-    var idx = head.childNodes.indexOf(node);
-    if (idx >= 0) {
-      var til = idx + 1;
-      var next = head.childNodes[til];
-      // remove newline text node as well
-      if (this.isBlankTextNode(next)) {
-        til++;
-      }
-      head.childNodes = head.childNodes.slice(0, idx).
-        concat(replacements, head.childNodes.slice(til));
-    } else {
-      this.removeImportAndNewline(node);
-      head.childNodes = head.childNodes.concat(replacements);
-    }
-  },
-
   // when removing imports, remove the newline after it as well
-  removeImportAndNewline: function removeImportAndNewline(importNode) {
+  removeImportAndNewline: function removeImportAndNewline(importNode, replacement) {
     var parent = importNode.parentNode;
     var nextIdx = parent.childNodes.indexOf(importNode) + 1;
     var next = parent.childNodes[nextIdx];
@@ -180,7 +162,11 @@ Vulcan.prototype = {
     if (this.isBlankTextNode(next)) {
       dom5.remove(next);
     }
-    dom5.remove(importNode);
+    if (replacement) {
+      dom5.replace(importNode, replacement);
+    } else {
+      dom5.remove(importNode);
+    }
   },
 
   isLicenseComment: function(node) {
@@ -190,7 +176,7 @@ Vulcan.prototype = {
     return false;
   },
 
-  flatten: function flatten(tree, bodyFragment, mainDocUrl, isMainDocument) {
+  flatten: function flatten(tree, isMainDoc) {
     var doc = tree.html.ast;
     var imports = tree.imports;
     var head = dom5.query(doc, matchers.head);
@@ -202,25 +188,38 @@ Vulcan.prototype = {
     }
     this.fixFakeExternalScripts(doc);
     this.pathResolver.acid(doc, tree.href);
+    var moveTarget = dom5.constructors.fragment();
+    var moveToBody = dom5.queryAll(head,
+      dom5.predicates.AND(
+        dom5.predicates.OR(
+          dom5.predicates.hasTagName('script'),
+          dom5.predicates.hasTagName('link')
+        ),
+        dom5.predicates.NOT(
+          matchers.polymerExternalStyle
+        )
+      )
+    );
+    moveToBody.forEach(function(m) {
+      // don't move nodes if inside a <template> content document
+      if (!dom5.nodeWalkPrior(m, dom5.isDocumentFragment)) {
+        dom5.append(moveTarget, m);
+      }
+    });
+    this.prepend(body, moveTarget);
     if (imports) {
-      // flatten all of <head> into one list
-      var flatHead = dom5.nodeWalkAll(head, function(){ return true; });
-      var currentBodyFragment = dom5.constructors.fragment();
       for (var i = 0, im, thisImport; i < imports.length; i++) {
         im = imports[i];
         thisImport = importNodes[i];
-        if (this.isDuplicateImport(im)) {
-          this.removeImportAndNewline(thisImport);
-          continue;
-        }
-        if (this.isStrippedImport(im)) {
+        if (this.isDuplicateImport(im) || this.isStrippedImport(im)) {
           this.removeImportAndNewline(thisImport);
           continue;
         }
         if (this.isExcludedImport(im)) {
           continue;
         }
-        var importDoc = this.flatten(im, currentBodyFragment, mainDocUrl);
+        var bodyFragment = dom5.constructors.fragment();
+        var importDoc = this.flatten(im);
         // rewrite urls
         this.pathResolver.resolvePaths(importDoc, im.href, tree.href);
         var importHead = dom5.query(importDoc, matchers.head);
@@ -229,74 +228,34 @@ Vulcan.prototype = {
         var importHeadChildren = importHead.childNodes;
         var importBodyChildren = importBody.childNodes;
         // make sure @license comments from import document make it into head
-        // check top level nodes
-        var licenseComments = importDoc.childNodes.filter(this.isLicenseComment);
         var importHtml = importHead.parentNode;
-        // check child nodes of <html>
-        licenseComments = licenseComments.concat(importHtml.childNodes.filter(this.isLicenseComment));
+        var licenseComments = importDoc.childNodes.concat(importHtml.childNodes).filter(this.isLicenseComment);
         // put license comments at the top of <head>
         importHeadChildren = licenseComments.concat(importHeadChildren);
-        // defer head children to be ordered properly in main document
-        if (importHeadChildren.length) {
-          this.pathResolver.resolvePaths(importHead, tree.href, mainDocUrl);
-          importHeadChildren.forEach(this.reparent(currentBodyFragment));
-          currentBodyFragment.childNodes = currentBodyFragment.childNodes.concat(importHeadChildren);
-        }
-        // defer body children to be inlined in-order
-        if (importBodyChildren.length) {
-          // adjust body urls to main document
-          this.pathResolver.resolvePaths(importBody, tree.href, mainDocUrl);
-          importBodyChildren.forEach(this.reparent(currentBodyFragment));
-          currentBodyFragment.childNodes = currentBodyFragment.childNodes.concat(importBodyChildren);
-        }
-        // to preserve script execution order, defer scripts after this import
-        // into body
-        var importInBody = Boolean(dom5.nodeWalkPrior(thisImport, matchers.body));
-        if (!importInBody) {
-          // only examine elements between this and the next import
-          var start = flatHead.indexOf(thisImport) + 1;
-          var end = flatHead.indexOf(importNodes[i + 1]);
-          var container = this.findElementsToMoveToBody(flatHead, start, end);
-          if (container.childNodes.length) {
-            this.pathResolver.resolvePaths(container, tree.href, mainDocUrl);
-            dom5.append(currentBodyFragment, container);
-          }
+        // move children of <head> and <body> into importer's <body>
+        var reparentFn = this.reparent(bodyFragment);
+        importHeadChildren.forEach(reparentFn);
+        importBodyChildren.forEach(reparentFn);
+        bodyFragment.childNodes = bodyFragment.childNodes.concat(
+          importHeadChildren,
+          importBodyChildren
+        );
+        // hide bodies of imports from rendering in main document
+        if (isMainDoc) {
+          this.hide(thisImport);
         }
-        // delete link
-        this.removeImportAndNewline(thisImport);
+        this.removeImportAndNewline(thisImport, bodyFragment);
       }
-      // resolve paths
-      if (!isMainDocument && currentBodyFragment.childNodes.length) {
-        // prepend this import document's <head> into body fragment
-        // preserves order when being flattened into a parent import
-        var hn = head.childNodes;
-        hn.forEach(this.reparent(currentBodyFragment));
-        this.pathResolver.resolvePaths(head, tree.href, mainDocUrl);
-        currentBodyFragment.childNodes = hn.concat(currentBodyFragment.childNodes);
-        head.childNodes = [];
-      }
-      dom5.append(bodyFragment, currentBodyFragment);
     }
     return doc;
   },
 
-  /**
-   * Return a document fragment with elements that need to be moved to <body> to
-   * preserve order of execution of scripts
-   */
-  findElementsToMoveToBody: function(flatHead, startIndex, endIndex) {
-    if (endIndex === -1) {
-      endIndex = flatHead.length;
-    }
-    var container = dom5.constructors.fragment();
-    for (var headidx = startIndex, el; headidx < endIndex; headidx++) {
-      el = flatHead[headidx];
-      // if the element is a script, move it to bodyFragment
-      if (matchers.JS(el)) {
-        dom5.append(container, el);
-      }
-    }
-    return container;
+  hide: function(node) {
+    var hidden = dom5.constructors.element('div');
+    dom5.setAttribute(hidden, 'hidden', '');
+    dom5.setAttribute(hidden, 'by-vulcanize', '');
+    this.removeImportAndNewline(node, hidden);
+    dom5.append(hidden, node);
   },
 
   prepend: function prepend(parent, node) {
@@ -440,15 +399,8 @@ Vulcan.prototype = {
     chain = chain.then(function(){
       return analyzer.metadataTree(target);
     }).then(function(tree) {
-      // hide bodies of imports from rendering
-      var bodyFragment = dom5.constructors.element('div');
-      dom5.setAttribute(bodyFragment, 'hidden', '');
-      dom5.setAttribute(bodyFragment, 'by-vulcanize', '');
-      var flatDoc = this.flatten(tree, bodyFragment, tree.href, true);
+      var flatDoc = this.flatten(tree, true);
       var body = dom5.query(flatDoc, matchers.body);
-      if (bodyFragment.childNodes.length) {
-        this.prepend(body, bodyFragment);
-      }
       // make sure there's a <meta charset> in the page to force UTF-8
       var meta = dom5.query(flatDoc, matchers.meta);
       var head = dom5.query(flatDoc, matchers.head);


Test patch:
diff --git a/test/html/complicated/A.html b/test/html/complicated/A.html
new file mode 100644
index 0000000..a9dedc3
--- /dev/null
+++ b/test/html/complicated/A.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<script src="A.js"></script>
+<link rel="import" href="B/B.html">
+<link rel="import" href="C/C.html">
+<script>
+A2
+</script>
diff --git a/test/html/complicated/A.js b/test/html/complicated/A.js
new file mode 100644
index 0000000..1e6fea0
--- /dev/null
+++ b/test/html/complicated/A.js
@@ -0,0 +1,1 @@
+A1
diff --git a/test/html/complicated/B/B.html b/test/html/complicated/B/B.html
new file mode 100644
index 0000000..2fba376
--- /dev/null
+++ b/test/html/complicated/B/B.html
@@ -0,0 +1,5 @@
+<link rel="import" href="../E/E.html">
+<script>
+B
+</script>
+<link rel="import" href="../D/D.html">
diff --git a/test/html/complicated/C/C.html b/test/html/complicated/C/C.html
new file mode 100644
index 0000000..500d45b
--- /dev/null
+++ b/test/html/complicated/C/C.html
@@ -0,0 +1,1 @@
+<script src="C.js"></script>
diff --git a/test/html/complicated/C/C.js b/test/html/complicated/C/C.js
new file mode 100644
index 0000000..3cc58df
--- /dev/null
+++ b/test/html/complicated/C/C.js
@@ -0,0 +1,1 @@
+C
diff --git a/test/html/complicated/D/D.html b/test/html/complicated/D/D.html
new file mode 100644
index 0000000..2027087
--- /dev/null
+++ b/test/html/complicated/D/D.html
@@ -0,0 +1,4 @@
+<link rel="import" href="../E/E.html">
+<script>
+D
+</script>
diff --git a/test/html/complicated/E/E.html b/test/html/complicated/E/E.html
new file mode 100644
index 0000000..3230e53
--- /dev/null
+++ b/test/html/complicated/E/E.html
@@ -0,0 +1,4 @@
+<link rel="import" href="../C/C.html">
+<script>
+E
+</script>
diff --git a/test/html/complicated/ordering.dot b/test/html/complicated/ordering.dot
new file mode 100644
index 0000000..49ced2d
--- /dev/null
+++ b/test/html/complicated/ordering.dot
@@ -0,0 +1,32 @@
+digraph imports {
+  fontname="sans-serif"
+  node [shape="record"];
+  edge [label="link rel='import'"]
+
+  title [shape="plaintext" label="Complicated Setup\nScripts should be executed in-order for all documents";]
+
+  A [label="A.html|{<js> A.js | <B> B/B.html | <C> C/C.html | 'A2'}"]
+  A:js -> A_js [label="script src"]
+  A:B -> B
+  A:C -> C
+
+  A_js [label="A.js|'A1'"]
+
+  B [label="B.html|{<E> ../E/E.html | 'B' | <D> ../D/D.html}"]
+  B:E -> E
+  B:D -> D
+
+  C [label="C.html|<js> C.js"]
+  C:js -> C_js [label="script src"]
+
+  C_js [label="C.js|'C'"]
+
+  D [label="D.html|{<E> ../E/E.html | 'D'}"]
+  D:E -> E
+
+  E [label="E.html|{<C> ../C/C.html | 'E'}"]
+  E:C -> C
+
+  build [label="build.html|{'A1'|'C'|'E'|'B'|'D'|'A2'}"]
+  A -> build [color="red"; label="inlined"]
+}
diff --git a/test/html/complicated/ordering.svg b/test/html/complicated/ordering.svg
new file mode 100644
index 0000000..19ce408
--- /dev/null
+++ b/test/html/complicated/ordering.svg
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.38.0 (20140413.2041)
+ -->
+<!-- Title: imports Pages: 1 -->
+<svg width="743pt" height="644pt"
+ viewBox="0.00 0.00 743.19 644.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 640)">
+<title>imports</title>
+<polygon fill="white" stroke="none" points="-4,4 -4,-640 739.191,-640 739.191,4 -4,4"/>
+<!-- title -->
+<g id="node1" class="node"><title>title</title>
+<text text-anchor="middle" x="157.875" y="-594.3" font-family="Times,serif" font-size="14.00">Complicated Setup</text>
+<text text-anchor="middle" x="157.875" y="-580.3" font-family="Times,serif" font-size="14.00">Scripts should be executed in&#45;order for all documents</text>
+</g>
+<!-- A -->
+<g id="node2" class="node"><title>A</title>
+<polygon fill="none" stroke="black" points="333.368,-547.5 333.368,-635.5 456.381,-635.5 456.381,-547.5 333.368,-547.5"/>
+<text text-anchor="middle" x="361.007" y="-587.3" font-family="Times,serif" font-size="14.00">A.html</text>
+<polyline fill="none" stroke="black" points="388.647,-547.5 388.647,-635.5 "/>
+<text text-anchor="middle" x="422.514" y="-620.3" font-family="Times,serif" font-size="14.00">A.js</text>
+<polyline fill="none" stroke="black" points="388.647,-613.5 456.381,-613.5 "/>
+<text text-anchor="middle" x="422.514" y="-598.3" font-family="Times,serif" font-size="14.00">B/B.html</text>
+<polyline fill="none" stroke="black" points="388.647,-591.5 456.381,-591.5 "/>
+<text text-anchor="middle" x="422.514" y="-576.3" font-family="Times,serif" font-size="14.00">C/C.html</text>
+<polyline fill="none" stroke="black" points="388.647,-569.5 456.381,-569.5 "/>
+<text text-anchor="middle" x="422.514" y="-554.3" font-family="Times,serif" font-size="14.00">&#39;A2&#39;</text>
+</g>
+<!-- A_js -->
+<g id="node3" class="node"><title>A_js</title>
+<polygon fill="none" stroke="black" points="571.323,-412.5 571.323,-448.5 648.426,-448.5 648.426,-412.5 571.323,-412.5"/>
+<text text-anchor="middle" x="590.797" y="-426.3" font-family="Times,serif" font-size="14.00">A.js</text>
+<polyline fill="none" stroke="black" points="610.271,-412.5 610.271,-448.5 "/>
+<text text-anchor="middle" x="629.349" y="-426.3" font-family="Times,serif" font-size="14.00">&#39;A1&#39;</text>
+</g>
+<!-- A&#45;&gt;A_js -->
+<g id="edge1" class="edge"><title>A:js&#45;&gt;A_js</title>
+<path fill="none" stroke="black" d="M457.875,-624.5C526.734,-624.5 540.848,-585.732 579.875,-529 594.405,-507.877 602.095,-479.465 606.035,-458.763"/>
+<polygon fill="black" stroke="black" points="609.517,-459.169 607.769,-448.719 602.619,-457.977 609.517,-459.169"/>
+<text text-anchor="middle" x="612.338" y="-517.8" font-family="Times,serif" font-size="14.00">script src</text>
+</g>
+<!-- B -->
+<g id="node4" class="node"><title>B</title>
+<polygon fill="none" stroke="black" points="418.537,-397.5 418.537,-463.5 553.212,-463.5 553.212,-397.5 418.537,-397.5"/>
+<text text-anchor="middle" x="445.79" y="-426.3" font-family="Times,serif" font-size="14.00">B.html</text>
+<polyline fill="none" stroke="black" points="473.043,-397.5 473.043,-463.5 "/>
+<text text-anchor="middle" x="513.128" y="-448.3" font-family="Times,serif" font-size="14.00">../E/E.html</text>
+<polyline fill="none" stroke="black" points="473.043,-441.5 553.212,-441.5 "/>
+<text text-anchor="middle" x="513.128" y="-426.3" font-family="Times,serif" font-size="14.00">&#39;B&#39;</text>
+<polyline fill="none" stroke="black" points="473.043,-419.5 553.212,-419.5 "/>
+<text text-anchor="middle" x="513.128" y="-404.3" font-family="Times,serif" font-size="14.00">../D/D.html</text>
+</g>
+<!-- A&#45;&gt;B -->
+<g id="edge2" class="edge"><title>A:B&#45;&gt;B</title>
+<path fill="none" stroke="black" d="M457.875,-602.5C483.908,-602.5 487.538,-524.339 487.159,-473.703"/>
+<polygon fill="black" stroke="black" points="490.658,-473.618 487.029,-463.664 483.659,-473.708 490.658,-473.618"/>
+<text text-anchor="middle" x="531.033" y="-517.8" font-family="Times,serif" font-size="14.00">link rel=&#39;import&#39;</text>
+</g>
+<!-- C -->
+<g id="node5" class="node"><title>C</title>
+<polygon fill="none" stroke="black" points="377.533,-87.5 377.533,-123.5 470.216,-123.5 470.216,-87.5 377.533,-87.5"/>
+<text text-anchor="middle" x="404.787" y="-101.3" font-family="Times,serif" font-size="14.00">C.html</text>
+<polyline fill="none" stroke="black" points="432.04,-87.5 432.04,-123.5 "/>
+<text text-anchor="middle" x="451.128" y="-101.3" font-family="Times,serif" font-size="14.00">C.js</text>
+</g>
+<!-- A&#45;&gt;C -->
+<g id="edge3" class="edge"><title>A:C&#45;&gt;C</title>
+<path fill="none" stroke="black" d="M457.875,-580.5C472.77,-580.5 462.567,-560.765 456.875,-547 445.218,-518.817 428.759,-520.949 409.875,-497 388.312,-469.655 366.875,-466.324 366.875,-431.5 366.875,-431.5 366.875,-431.5 366.875,-195.5 366.875,-170.901 382.506,-147.659 397.398,-131.098"/>
+<polygon fill="black" stroke="black" points="400.235,-133.193 404.577,-123.528 395.156,-128.376 400.235,-133.193"/>
+<text text-anchor="middle" x="412.033" y="-287.3" font-family="Times,serif" font-size="14.00">link rel=&#39;import&#39;</text>
+</g>
+<!-- build -->
+<g id="node9" class="node"><title>build</title>
+<polygon fill="none" stroke="black" points="226.823,-364.5 226.823,-496.5 338.926,-496.5 338.926,-364.5 226.823,-364.5"/>
+<text text-anchor="middle" x="263.797" y="-426.3" font-family="Times,serif" font-size="14.00">build.html</text>
+<polyline fill="none" stroke="black" points="300.771,-364.5 300.771,-496.5 "/>
+<text text-anchor="middle" x="319.849" y="-481.3" font-family="Times,serif" font-size="14.00">&#39;A1&#39;</text>
+<polyline fill="none" stroke="black" points="300.771,-474.5 338.926,-474.5 "/>
+<text text-anchor="middle" x="319.849" y="-459.3" font-family="Times,serif" font-size="14.00">&#39;C&#39;</text>
+<polyline fill="none" stroke="black" points="300.771,-452.5 338.926,-452.5 "/>
+<text text-anchor="middle" x="319.849" y="-437.3" font-family="Times,serif" font-size="14.00">&#39;E&#39;</text>
+<polyline fill="none" stroke="black" points="300.771,-430.5 338.926,-430.5 "/>
+<text text-anchor="middle" x="319.849" y="-415.3" font-family="Times,serif" font-size="14.00">&#39;B&#39;</text>
+<polyline fill="none" stroke="black" points="300.771,-408.5 338.926,-408.5 "/>
+<text text-anchor="middle" x="319.849" y="-393.3" font-family="Times,serif" font-size="14.00">&#39;D&#39;</text>
+<polyline fill="none" stroke="black" points="300.771,-386.5 338.926,-386.5 "/>
+<text text-anchor="middle" x="319.849" y="-371.3" font-family="Times,serif" font-size="14.00">&#39;A2&#39;</text>
+</g>
+<!-- A&#45;&gt;build -->
+<g id="edge9" class="edge"><title>A&#45;&gt;build</title>
+<path fill="none" stroke="red" d="M333.13,-550.224C326.011,-543.748 319.384,-536.637 313.992,-529 309.003,-521.934 304.786,-514.03 301.228,-505.862"/>
+<polygon fill="red" stroke="red" points="304.464,-504.53 297.485,-496.559 297.97,-507.142 304.464,-504.53"/>
+<text text-anchor="middle" x="333.316" y="-517.8" font-family="Times,serif" font-size="14.00">inlined</text>
+</g>
+<!-- E -->
+<g id="node6" class="node"><title>E</title>
+<polygon fill="none" stroke="black" points="471.702,-174.5 471.702,-218.5 604.047,-218.5 604.047,-174.5 471.702,-174.5"/>
+<text text-anchor="middle" x="498.562" y="-192.3" font-family="Times,serif" font-size="14.00">E.html</text>
+<polyline fill="none" stroke="black" points="525.423,-174.5 525.423,-218.5 "/>
+<text text-anchor="middle" x="564.735" y="-203.3" font-family="Times,serif" font-size="14.00">../C/C.html</text>
+<polyline fill="none" stroke="black" points="525.423,-196.5 604.047,-196.5 "/>
+<text text-anchor="middle" x="564.735" y="-181.3" font-family="Times,serif" font-size="14.00">&#39;E&#39;</text>
+</g>
+<!-- B&#45;&gt;E -->
+<g id="edge4" class="edge"><title>B:E&#45;&gt;E</title>
+<path fill="none" stroke="black" d="M553.875,-452.5C563.748,-452.5 555.705,-371.708 561.875,-364 578.211,-343.59 601.283,-366.204 617.875,-346 648.775,-308.371 655.584,-277.711 628.875,-237 624.718,-230.664 619.301,-225.339 613.181,-220.865"/>
+<polygon fill="black" stroke="black" points="614.761,-217.72 604.452,-215.276 610.987,-223.616 614.761,-217.72"/>
+<text text-anchor="middle" x="690.033" y="-287.3" font-family="Times,serif" font-size="14.00">link rel=&#39;import&#39;</text>
+</g>
+<!-- D -->
+<g id="node7" class="node"><title>D</title>
+<polygon fill="none" stroke="black" points="474.709,-269.5 474.709,-313.5 607.04,-313.5 607.04,-269.5 474.709,-269.5"/>
+<text text-anchor="middle" x="502.349" y="-287.3" font-family="Times,serif" font-size="14.00">D.html</text>
+<polyline fill="none" stroke="black" points="529.988,-269.5 529.988,-313.5 "/>
+<text text-anchor="middle" x="568.514" y="-298.3" font-family="Times,serif" font-size="14.00">../E/E.html</text>
+<polyline fill="none" stroke="black" points="529.988,-291.5 607.04,-291.5 "/>
+<text text-anchor="middle" x="568.514" y="-276.3" font-family="Times,serif" font-size="14.00">&#39;D&#39;</text>
+</g>
+<!-- B&#45;&gt;D -->
+<g id="edge5" class="edge"><title>B:D&#45;&gt;D</title>
+<path fill="none" stroke="black" d="M512.875,-396.5C512.875,-371.111 520.751,-343.397 528.15,-322.967"/>
+<polygon fill="black" stroke="black" points="531.442,-324.157 531.706,-313.565 524.894,-321.68 531.442,-324.157"/>
+<text text-anchor="middle" x="569.033" y="-334.8" font-family="Times,serif" font-size="14.00">link rel=&#39;import&#39;</text>
+</g>
+<!-- C_js -->
+<g id="node8" class="node"><title>C_js</title>
+<polygon fill="none" stroke="black" points="416.595,-0.5 416.595,-36.5 485.154,-36.5 485.154,-0.5 416.595,-0.5"/>
+<text text-anchor="middle" x="435.683" y="-14.3" font-family="Times,serif" font-size="14.00">C.js</text>
+<polyline fill="none" stroke="black" points="454.771,-0.5 454.771,-36.5 "/>
+<text text-anchor="middle" x="469.962" y="-14.3" font-family="Times,serif" font-size="14.00">&#39;C&#39;</text>
+</g>
+<!-- C&#45;&gt;C_js -->
+<g id="edge6" class="edge"><title>C:js&#45;&gt;C_js</title>
+<path fill="none" stroke="black" d="M450.875,-87C450.875,-73.767 450.875,-59.0747 450.875,-46.7852"/>
+<polygon fill="black" stroke="black" points="454.375,-46.701 450.875,-36.701 447.375,-46.701 454.375,-46.701"/>
+<text text-anchor="middle" x="476.338" y="-57.8" font-family="Times,serif" font-size="14.00">script src</text>
+</g>
+<!-- E&#45;&gt;C -->
+<g id="edge8" class="edge"><title>E:C&#45;&gt;C</title>
+<path fill="none" stroke="black" d="M564.875,-219.5C564.875,-228.208 597.969,-224.735 604.047,-218.5 617.852,-204.338 615.315,-190.254 604.047,-174 576.445,-134.184 522.285,-117.817 480.52,-111.11"/>
+<polygon fill="black" stroke="black" points="480.866,-107.623 470.464,-109.64 479.853,-114.549 480.866,-107.623"/>
+<text text-anchor="middle" x="632.033" y="-144.8" font-family="Times,serif" font-size="14.00">link rel=&#39;import&#39;</text>
+</g>
+<!-- D&#45;&gt;E -->
+<g id="edge7" class="edge"><title>D:E&#45;&gt;E</title>
+<path fill="none" stroke="black" d="M568.875,-314.5C568.875,-322.984 601.12,-319.577 607.04,-313.5 620.841,-299.333 619.117,-284.662 607.04,-269 587.823,-244.079 557.934,-275.798 538.558,-251 533.667,-244.74 531.967,-236.692 531.873,-228.749"/>
+<polygon fill="black" stroke="black" points="535.381,-228.733 532.54,-218.526 528.396,-228.277 535.381,-228.733"/>
+<text text-anchor="middle" x="583.033" y="-239.8" font-family="Times,serif" font-size="14.00">link rel=&#39;import&#39;</text>
+</g>
+</g>
+</svg>
diff --git a/test/test.js b/test/test.js
index a7e8fff..3588e5a 100644
--- a/test/test.js
+++ b/test/test.js
@@ -1042,4 +1042,30 @@ suite('Vulcan', function() {
     });
   });
 
+  suite('Regression Testing', function() {
+    test('Complicated Ordering', function(done) {
+      // refer to https://github.com/Polymer/vulcanize/tree/master/test/html/complicated/ordering.svg
+      // for visual reference on the document structure for this example
+      process('test/html/complicated/A.html', function(err, doc) {
+        if (err) {
+          return done(err);
+        }
+        assert(doc);
+        var expected = [
+          'A1',
+          'C',
+          'E',
+          'B',
+          'D',
+          'A2'
+        ];
+        var scripts = dom5.queryAll(doc, preds.hasTagName('script'));
+        var contents = scripts.map(function(s){
+          return dom5.getTextContent(s).trim();
+        });
+        assert.deepEqual(contents, expected);
+        done();
+      }, {inlineScripts: true});
+    });
+  });
 });