Repository: buxlabs/boxwood
Pull request #635 (2020-04-27 20:29:06)

Join non processed scripts


Patch:
diff --git a/src/Renderer.js b/src/Renderer.js
index 9bb921f..cdc1754 100644
--- a/src/Renderer.js
+++ b/src/Renderer.js
@@ -52,6 +52,7 @@ class Renderer {
         statistics.translations.push(asset)
       }
     })
+    const scripts = []
     const styles = []
     const store = {}
     const translations = {}
@@ -98,13 +99,17 @@ class Renderer {
     const severities = warnings.map(warning => warning.severity)
     if (!severities.includes('critical')) {
       walk(htmltree, async fragment => {
-        await collect({ source, tree, fragment, assets, variables, filters, components, styles, translations, plugins, store, depth, options, promises, errors, warnings })
+        await collect({ source, tree, fragment, assets, variables, filters, components, styles, scripts, translations, plugins, store, depth, options, promises, errors, warnings })
       })
       await Promise.all(promises)
       const style = unique(styles).join(' ')
       if (style) {
         tree.append(getTemplateAssignmentExpression(TEMPLATE_VARIABLE, getLiteral(`<style>${style}</style>`)))
       }
+      const script = unique(scripts).join(' ')
+      if (script) {
+        tree.append(getTemplateAssignmentExpression(TEMPLATE_VARIABLE, getLiteral(`<script>${script}</script>`)))
+      }
       const used = []
       unique(filters).forEach(name => {
         const filter = getFilter(name, translations, options)
diff --git a/src/tags/script.js b/src/tags/script.js
index 900d358..043f2e5 100644
--- a/src/tags/script.js
+++ b/src/tags/script.js
@@ -10,23 +10,14 @@ const { isCurlyTag } = require('../utilities/string')
 const { convertAttribute } = require('../utilities/convert')
 let asyncCounter = 0
 
-module.exports = async function ({ tree, keys, attrs, fragment, assets, variables, promises, warnings, filters, translations, languages, append, options }) {
+module.exports = async function ({ tree, keys, attrs, fragment, assets, variables, promises, warnings, filters, translations, languages, append, scripts, options }) {
   if (keys.includes('inline') || options.inline.includes('scripts')) {
     if (keys.includes('src')) {
       const { value: path } = attrs.find(attr => attr.key === 'src')
       const asset = findAsset(path, assets, options)
       if (!asset) return
-      let content = '<script'
-      fragment.attributes.forEach(attribute => {
-        const { key, value } = attribute
-        if (key !== 'src' && key !== 'inline') {
-          content += ` ${key}="${value}"`
-        }
-      })
-      content += '>'
-      content += asset.source.trim()
-      content += '</script>'
-      tree.append(getTemplateAssignmentExpression(options.variables.template, getLiteral(content)))
+      const content = asset.source.trim()
+      scripts.push(content)
     } else {
       const leaf = fragment.children[0]
       leaf.used = true
@@ -35,7 +26,7 @@ module.exports = async function ({ tree, keys, attrs, fragment, assets, variable
       ast.body.forEach(node => tree.append(node))
     }
   } else if (keys.includes('polyfills')) {
-    let content = '<script>'
+    let content = ''
     const { value } = attrs.find(attr => attr.key === 'polyfills')
     const ast = new AbstractSyntaxTree(value)
     const polyfills = AbstractSyntaxTree.serialize(ast.body[0].expression)
@@ -51,8 +42,7 @@ module.exports = async function ({ tree, keys, attrs, fragment, assets, variable
       node.used = true
       content += node.content
     })
-    content += '</script>'
-    tree.append(getTemplateAssignmentExpression(options.variables.template, getLiteral(content)))
+    scripts.push(content)
   } else if (keys.includes('scoped')) {
     const leaf = fragment.children[0]
     if (!leaf) return
@@ -132,7 +122,7 @@ module.exports = async function ({ tree, keys, attrs, fragment, assets, variable
         })
       }
     }
-  } else {
+  } else if (keys.includes('src')) {
     append(getLiteral('<script'))
     fragment.attributes.forEach(attribute => {
       if (isCurlyTag(attribute.value)) {
@@ -151,5 +141,11 @@ module.exports = async function ({ tree, keys, attrs, fragment, assets, variable
       append(getLiteral(node.content))
     })
     append(getLiteral('</script>'))
+  } else {
+    fragment.children.forEach(node => {
+      node.used = true
+      const { content } = node
+      scripts.push(content)
+    })
   }
 }
diff --git a/src/utilities/collect.js b/src/utilities/collect.js
index fb653d0..5b6c015 100644
--- a/src/utilities/collect.js
+++ b/src/utilities/collect.js
@@ -234,10 +234,10 @@ function resolveComponent (content, path, component, fragment, queue, plugins, w
   return { fragment, localVariables }
 }
 
-async function collect ({ source, tree, fragment, assets, variables, filters, components, styles, translations, plugins, store, depth, options, promises, errors, warnings }) {
+async function collect ({ source, tree, fragment, assets, variables, filters, components, scripts, styles, translations, plugins, store, depth, options, promises, errors, warnings }) {
   function collectChildren (fragment, ast) {
     walk(fragment, async current => {
-      await collect({ source, tree: ast, fragment: current, assets, variables, filters, components, styles, translations, plugins, store, depth, options, promises, errors, warnings })
+      await collect({ source, tree: ast, fragment: current, assets, variables, filters, components, scripts, styles, translations, plugins, store, depth, options, promises, errors, warnings })
     })
   }
   function append (node) {
@@ -316,7 +316,7 @@ async function collect ({ source, tree, fragment, assets, variables, filters, co
     } else if (tag === 'style') {
       tags.style({ fragment, styles })
     } else if (tag === 'script') {
-      tags.script({ tree, fragment, keys, attrs, assets, variables, promises, warnings, filters, translations, languages, append, options })
+      tags.script({ tree, fragment, keys, attrs, assets, variables, promises, warnings, filters, translations, languages, append, scripts, options })
     } else if (tag === 'template') {
       tags.template({ tree, fragment, options })
     } else if (tag === 'data') {


Test patch:
diff --git a/test/fixtures/acceptance/accordion/actual.html b/test/fixtures/acceptance/accordion/actual.html
new file mode 100644
index 0000000..540da32
--- /dev/null
+++ b/test/fixtures/acceptance/accordion/actual.html
@@ -0,0 +1,4 @@
+<import accordion from="components/accordion.html" />
+
+<accordion title="foo">bar</accordion>
+<accordion title="baz">qux</accordion>
diff --git a/test/fixtures/acceptance/accordion/components/accordion.html b/test/fixtures/acceptance/accordion/components/accordion.html
new file mode 100644
index 0000000..570f81f
--- /dev/null
+++ b/test/fixtures/acceptance/accordion/components/accordion.html
@@ -0,0 +1,16 @@
+<div class="accordion-toggle">{title}</div>
+<div class="accordion"><slot /></div>
+<style scoped>
+.accordion.hidden {
+  display: none;
+}
+</style>
+<script>
+const accordions = document.getElementsByClassName('accordion-toggle')
+accordions.forEach(function (accordion) {
+  accordion.addEventListener("click", function (event) {
+    const sibling = this.nextElementSibling
+    sibling.classList.toggle('hidden')
+  })
+})
+</script>
diff --git a/test/fixtures/acceptance/accordion/data.json b/test/fixtures/acceptance/accordion/data.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/test/fixtures/acceptance/accordion/data.json
@@ -0,0 +1,1 @@
+{}
diff --git a/test/fixtures/acceptance/accordion/expected.html b/test/fixtures/acceptance/accordion/expected.html
new file mode 100644
index 0000000..5918590
--- /dev/null
+++ b/test/fixtures/acceptance/accordion/expected.html
@@ -0,0 +1,18 @@
+<div class="accordion-toggle">foo</div>
+<div class="scope-2305847944 accordion">bar</div>
+<div class="accordion-toggle">baz</div>
+<div class="scope-2305847944 accordion">qux</div>
+<style>
+.scope-2305847944.accordion.hidden {
+  display: none
+}
+</style>
+<script>
+const accordions = document.getElementsByClassName('accordion-toggle')
+accordions.forEach(function (accordion) {
+  accordion.addEventListener("click", function (event) {
+    const sibling = this.nextElementSibling
+    sibling.classList.toggle('hidden')
+  })
+})
+</script>
diff --git a/test/fixtures/acceptance/admin-page/expected.html b/test/fixtures/acceptance/admin-page/expected.html
index 7d28a27..1f1ebc6 100644
--- a/test/fixtures/acceptance/admin-page/expected.html
+++ b/test/fixtures/acceptance/admin-page/expected.html
@@ -64,23 +64,7 @@
                 </ul>
               </div>
             </div>
-          </div>
-          <script>
-            Array.from(document.querySelector('.dropdown.list').childNodes).filter(node => node.localName === 'li')
-              .forEach(dropdownItem => {
-                dropdownItem.addEventListener('click', ({ target }) => {
-                  const dropdownContainer = target.closest('.dropdown.container')
-                  if (dropdownContainer) {
-                    dropdownContainer.classList.toggle('open')
-                    const dropdownList = dropdownContainer.parentElement.querySelector('ul')
-                    if (dropdownList) dropdownList.classList.toggle('undisplayed')
-                  }
-                })
-              })
-            document.querySelector('#sidebar-toggle').addEventListener('click', event => {
-              document.querySelector('#sidebar').classList.toggle('undisplayed')
-            })
-          </script>          
+          </div>         
           <div class="nine wide column" style="flex: 1;">
             <h2 class="purple">Issues list</h2>
             <div class="ui fluid concise input">
@@ -124,7 +108,26 @@
   </div>
 </body>
 </html>
+<style>
+  .scope-2654693148.unstyled.dropdown.list li a.active { 
+    color: #4183c4
+  }
+</style>
 <script>
+  Array.from(document.querySelector('.dropdown.list').childNodes).filter(node => node.localName === 'li')
+    .forEach(dropdownItem => {
+      dropdownItem.addEventListener('click', ({ target }) => {
+        const dropdownContainer = target.closest('.dropdown.container')
+        if (dropdownContainer) {
+          dropdownContainer.classList.toggle('open')
+          const dropdownList = dropdownContainer.parentElement.querySelector('ul')
+          if (dropdownList) dropdownList.classList.toggle('undisplayed')
+        }
+      })
+    })
+  document.querySelector('#sidebar-toggle').addEventListener('click', event => {
+    document.querySelector('#sidebar').classList.toggle('undisplayed')
+  })
   const searchInput = document.getElementById('search')
   const issues = Array.from(document.getElementsByClassName('ui task grid'))
   searchInput.addEventListener('keyup', ({ target }) => {
@@ -134,9 +137,4 @@
       issue.classList.toggle('undisplayed', !title.innerText.includes(value))
     })
   })
-</script>
-<style>
-  .scope-2654693148.unstyled.dropdown.list li a.active { 
-    color: #4183c4
-  }
-</style>
+</script> 
diff --git a/test/fixtures/acceptance/app-page/expected.html b/test/fixtures/acceptance/app-page/expected.html
index 05386d1..7062fe1 100644
--- a/test/fixtures/acceptance/app-page/expected.html
+++ b/test/fixtures/acceptance/app-page/expected.html
@@ -22,14 +22,6 @@
         <h3>Interesujący slogan</h3>
       </div> 
     </div>
-    <script>
-      const root = document.querySelector('.logo')
-      document.querySelector('.back').addEventListener('click', () => {
-        const { referrer } = document
-        if (referrer && referrer.startsWith(window.location.origin)) return this.history.back()
-        window.location.href = root.href
-      })
-    </script>
     <div class="ui container black">
       <div class="ui stackable grid">
         <div class="row">
@@ -165,3 +157,11 @@
     text-align: justify
   }
 </style>
+<script>
+  const root = document.querySelector('.logo')
+  document.querySelector('.back').addEventListener('click', () => {
+    const { referrer } = document
+    if (referrer && referrer.startsWith(window.location.origin)) return this.history.back()
+    window.location.href = root.href
+  })
+</script>
diff --git a/test/fixtures/acceptance/tool-page/expected.html b/test/fixtures/acceptance/tool-page/expected.html
index 94861e0..3d96763 100644
--- a/test/fixtures/acceptance/tool-page/expected.html
+++ b/test/fixtures/acceptance/tool-page/expected.html
@@ -96,27 +96,6 @@
   </div>
 </body>
 </html>
-<script>
-  const filter = document.getElementById('filter')
-  const searchables = document.querySelectorAll('[data-searchable="searchable"]')
-  filter.addEventListener('keyup', event => {
-    let { value } = event.target
-    value = value.trim().toLowerCase()
-    for (let i = 0; i < searchables.length; i++) {
-      const searchable = searchables[i]
-      const header = searchable.querySelector('h2')
-      const list = searchable.querySelector('ul')
-      const { children } = list
-      for (let j = 0; j < children.length; j++) {
-        const child = children[j]
-        const text = child.innerText.toLowerCase()
-        child.classList.toggle('undisplayed', !text.includes(value))
-      }
-      const hiddenLength = list.querySelectorAll('li.undisplayed').length
-      header.classList.toggle('undisplayed', hiddenLength === children.length)
-    }
-  })
-</script>
 <style>
   .sidebar {
     position: fixed;
@@ -144,4 +123,25 @@
   .light.green {
     color: #00ffa5;
   }  
-</style>
\ No newline at end of file
+</style>
+<script>
+  const filter = document.getElementById('filter')
+  const searchables = document.querySelectorAll('[data-searchable="searchable"]')
+  filter.addEventListener('keyup', event => {
+    let { value } = event.target
+    value = value.trim().toLowerCase()
+    for (let i = 0; i < searchables.length; i++) {
+      const searchable = searchables[i]
+      const header = searchable.querySelector('h2')
+      const list = searchable.querySelector('ul')
+      const { children } = list
+      for (let j = 0; j < children.length; j++) {
+        const child = children[j]
+        const text = child.innerText.toLowerCase()
+        child.classList.toggle('undisplayed', !text.includes(value))
+      }
+      const hiddenLength = list.querySelectorAll('li.undisplayed').length
+      header.classList.toggle('undisplayed', hiddenLength === children.length)
+    }
+  })
+</script>
diff --git a/test/spec/acceptance.spec.js b/test/spec/acceptance.spec.js
index 9ba55b0..cb38f13 100644
--- a/test/spec/acceptance.spec.js
+++ b/test/spec/acceptance.spec.js
@@ -206,6 +206,11 @@ test('acceptance: routes', async assert => {
   assert.deepEqual(actual, expected)
 })
 
+test('acceptance: accordion', async assert => {
+  const { actual, expected } = await suite('accordion')
+  assert.deepEqual(actual, expected)
+})
+
 test.skip('acceptance: slot as a variable', async assert => {
   const { actual, expected } = await suite('slot-as-variable')
   assert.deepEqual(actual, expected)
diff --git a/test/spec/basic.spec.js b/test/spec/basic.spec.js
index a186e41..707af39 100644
--- a/test/spec/basic.spec.js
+++ b/test/spec/basic.spec.js
@@ -380,7 +380,7 @@ test('basic', async assert => {
   assert.deepEqual(template({}, escape), '')
 
   var { template } = await compile('<script></script>')
-  assert.deepEqual(template({}, escape), '<script></script>')
+  assert.deepEqual(template({}, escape), '')
 
   var { template } = await compile('<script src="foo.js" defer></script>')
   assert.deepEqual(template({}, escape), '<script src="foo.js" defer></script>')