Repository: maizzle/framework
Pull request #813 (2022-10-20 11:08:01)

[4.x] Fixes issues with the inlineCSS transformer
This PR fixes some issues with CSS inlining:

- fixed an issue where using lowercase tag names in `inlineCSS` did not work
- fixed an issue where `styleToAttribute` was not being applied



Patch:
diff --git a/src/transformers/inlineCss.js b/src/transformers/inlineCss.js
index 8794315..db9157e 100644
--- a/src/transformers/inlineCss.js
+++ b/src/transformers/inlineCss.js
@@ -7,14 +7,17 @@ module.exports = async (html, config = {}, direct = false) => {
   }
 
   const options = direct ? config : get(config, 'inlineCSS', {})
+  // Default `removeStyleTags` to false so we can preserve
+  // CSS selectors that are not present in the HTML
   const removeStyleTags = get(options, 'removeStyleTags', false)
   const css = get(config, 'customCSS', false)
 
   if (get(config, 'inlineCSS') === true || !isEmpty(options)) {
+    options.applyAttributesTableElements = true
     juice.styleToAttribute = get(options, 'styleToAttribute', {'vertical-align': 'valign'})
 
-    juice.widthElements = get(options, 'applyWidthAttributes', [])
-    juice.heightElements = get(options, 'applyHeightAttributes', [])
+    juice.widthElements = get(options, 'applyWidthAttributes', []).map(i => i.toUpperCase())
+    juice.heightElements = get(options, 'applyHeightAttributes', []).map(i => i.toUpperCase())
 
     juice.excludedProperties = ['--tw-shadow']
 
@@ -28,7 +31,9 @@ module.exports = async (html, config = {}, direct = false) => {
       })
     }
 
-    html = css ? juice.inlineContent(html, css, {removeStyleTags}) : juice(html, {removeStyleTags})
+    html = css ?
+      juice.inlineContent(html, css, {removeStyleTags, ...options}) :
+      juice(html, {removeStyleTags, ...options})
 
     return html
   }
diff --git a/src/transformers/removeInlineSizes.js b/src/transformers/removeInlineSizes.js
index 2fc377a..5f497f5 100644
--- a/src/transformers/removeInlineSizes.js
+++ b/src/transformers/removeInlineSizes.js
@@ -19,12 +19,11 @@ module.exports = async (html, config = {}, direct = false) => {
 const removeInlineSizes = (mappings = {}) => tree => {
   const process = node => {
     const attrs = parseAttrs(node.attrs)
-    const tag = node.tag ? node.tag.toUpperCase() : ''
 
     Object.entries(mappings).forEach(([attribute, tags]) => {
-      tags = Object.values(tags)
+      tags = Object.values(tags).map(tag => tag.toLowerCase())
 
-      if (!tags.includes(tag)) {
+      if (!tags.includes(node.tag)) {
         return node
       }
 


Test patch:
diff --git a/test/test-transformers.js b/test/test-transformers.js
index 05f11ed..56641a6 100644
--- a/test/test-transformers.js
+++ b/test/test-transformers.js
@@ -13,13 +13,24 @@ const expected = file => readFile('expected/transformers', file)
 
 test('remove inline sizes', async t => {
   const options = {
-    width: ['TD'],
-    height: ['TD']
+    width: ['table'],
+    height: ['td']
   }
 
-  const html = await Maizzle.removeInlineSizes('<td style="width:100%;height:10px;">test</td>', options)
+  const html = await Maizzle.removeInlineSizes(`
+    <table style="width: 10px; height: auto;">
+      <tr>
+        <td style="width: 100%; height: 10px;">test</td>
+      </tr>
+    </table>`,
+  options)
 
-  t.is(html, '<td style="">test</td>')
+  t.is(html, `
+    <table style="height: auto">
+      <tr>
+        <td style="width: 100%">test</td>
+      </tr>
+    </table>`)
 })
 
 test('remove inline background-color', async t => {
@@ -47,20 +58,58 @@ test('remove inline background-color (with tags)', async t => {
 })
 
 test('inline CSS', async t => {
-  const html = `<div class="foo bar">test</div>`
+  const html = `
+    <table class="w-1 h-1 text-center">
+      <tr>
+        <td class="foo bar h-1">test</td>
+      </tr>
+    </table>`
   const css = `
+    .w-1 {width: 4px}
+    .h-1 {height: 4px}
     .foo {color: red}
     .bar {cursor: pointer}
+    .text-center {text-align: center}
   `
 
-  const result = await Maizzle.inlineCSS(html, {
+  const html2 = `
+  <html>
+    <head>
+      <style>${css}</style>
+    </head>
+    <body>
+      <table class="w-1 h-1 text-center">
+        <tr>
+          <td class="foo bar h-1">test</td>
+        </tr>
+      </table>
+    </body>
+  </html>`
+
+  const result1 = await Maizzle.inlineCSS(html, {
     customCSS: css,
     removeStyleTags: false,
     styleToAttribute: {
       'text-align': 'align'
     },
-    applyWidthAttributes: ['TABLE'],
-    applyHeightAttributes: ['TD'],
+    applyWidthAttributes: ['table'],
+    applyHeightAttributes: ['td'],
+    mergeLonghand: ['div'],
+    excludedProperties: ['cursor'],
+    codeBlocks: {
+      RB: {
+        start: '<%',
+        end: '%>'
+      }
+    }
+  })
+  const result2 = await Maizzle.inlineCSS(html2, {
+    removeStyleTags: false,
+    styleToAttribute: {
+      'text-align': 'align'
+    },
+    applyWidthAttributes: ['table'],
+    applyHeightAttributes: ['td'],
     mergeLonghand: ['div'],
     excludedProperties: ['cursor'],
     codeBlocks: {
@@ -71,7 +120,32 @@ test('inline CSS', async t => {
     }
   })
 
-  t.is(result, '<div class="foo bar" style="color: red;">test</div>')
+  t.is(result1, `
+    <table class="w-1 h-1 text-center" style="width: 4px; height: 4px; text-align: center;" width="4" align="center">
+      <tr>
+        <td class="foo bar h-1" style="height: 4px; color: red;" height="4">test</td>
+      </tr>
+    </table>`)
+
+  t.is(result2, `
+  <html>
+    <head>
+      <style>
+    .w-1 {width: 4px}
+    .h-1 {height: 4px}
+    .foo {color: red}
+    .bar {cursor: pointer}
+    .text-center {text-align: center}
+  </style>
+    </head>
+    <body>
+      <table class="w-1 h-1 text-center" style="width: 4px; height: 4px; text-align: center;" width="4" align="center">
+        <tr>
+          <td class="foo bar h-1" style="height: 4px; color: red;" height="4">test</td>
+        </tr>
+      </table>
+    </body>
+  </html>`)
 })
 
 test('inline CSS (disabled)', async t => {