Repository: maizzle/framework
Pull request #695 (2022-05-26 15:11:47)

refactor: merge inline longhand
**This is a v4.0 breaking change.**

This PR refactors `inlineCSS.mergeLonghand` by extracting it to its own Transformer.

This makes it possible to transform longhand inline CSS to shorthand even when CSS inlining is disabled.

```diff
module.exports = {
-  inlineCSS: {
-    mergeLonghand: true
-  }
+  shorthandInlineCSS: true
}
```

The Transformer does not run by default, you need to explicitly enable it.

Of course, you may customize which tags it should be enabled for:

```js
module.exports = {
  shorthandInlineCSS: ['table', 'div'] // enable only for these tags
}
```



Patch:
diff --git a/src/transformers/index.js b/src/transformers/index.js
index f0fa219..14f4fda 100644
--- a/src/transformers/index.js
+++ b/src/transformers/index.js
@@ -14,6 +14,7 @@ const removeAttributes = require('./removeAttributes')
 const attributeToStyle = require('./attributeToStyle')
 const removeInlineSizes = require('./removeInlineSizes')
 const applyExtraAttributes = require('./extraAttributes')
+const shorthandInlineCSS = require('./shorthandInlineCSS')
 const removeInlinedClasses = require('./removeInlinedSelectors')
 const removeInlineBgColor = require('./removeInlineBackgroundColor')
 
@@ -24,6 +25,7 @@ exports.process = async (html, config) => {
   html = await preventWidows(html, config)
   html = await attributeToStyle(html, config)
   html = await inline(html, config)
+  html = await shorthandInlineCSS(html, config)
   html = await removeInlinedClasses(html, config)
   html = await removeUnusedCSS(html, config)
   html = await removeInlineSizes(html, config)
@@ -56,5 +58,6 @@ exports.attributeToStyle = (html, config) => attributeToStyle(html, config, true
 exports.removeInlineSizes = (html, config) => removeInlineSizes(html, config, true)
 exports.applyBaseImageUrl = (html, config) => applyBaseImageUrl(html, config, true)
 exports.removeInlinedClasses = (html, config) => removeInlinedClasses(html, config)
+exports.shorthandInlineCSS = (html, config) => shorthandInlineCSS(html, config)
 exports.removeInlineBgColor = (html, config) => removeInlineBgColor(html, config, true)
 exports.applyExtraAttributes = (html, config) => applyExtraAttributes(html, config, true)
diff --git a/src/transformers/inlineCss.js b/src/transformers/inlineCss.js
index b52440a..8794315 100644
--- a/src/transformers/inlineCss.js
+++ b/src/transformers/inlineCss.js
@@ -1,7 +1,5 @@
 const juice = require('juice')
-const posthtml = require('posthtml')
 const {get, isObject, isEmpty} = require('lodash')
-const mergeLonghand = require('posthtml-postcss-merge-longhand')
 
 module.exports = async (html, config = {}, direct = false) => {
   if (get(config, 'inlineCSS') === false) {
@@ -32,17 +30,6 @@ module.exports = async (html, config = {}, direct = false) => {
 
     html = css ? juice.inlineContent(html, css, {removeStyleTags}) : juice(html, {removeStyleTags})
 
-    const posthtmlOptions = get(config, 'build.posthtml.options', {})
-    const mergeLonghandConfig = get(options, 'mergeLonghand', [])
-
-    if (typeof mergeLonghandConfig === 'boolean' && mergeLonghandConfig) {
-      html = await posthtml([mergeLonghand()]).process(html, posthtmlOptions).then(result => result.html)
-    }
-
-    if (isObject(mergeLonghandConfig) && !isEmpty(mergeLonghandConfig)) {
-      html = await posthtml([mergeLonghand({tags: mergeLonghandConfig})]).process(html, posthtmlOptions).then(result => result.html)
-    }
-
     return html
   }
 
diff --git a/src/transformers/shorthandInlineCSS.js b/src/transformers/shorthandInlineCSS.js
new file mode 100644
index 0000000..df8a14e
--- /dev/null
+++ b/src/transformers/shorthandInlineCSS.js
@@ -0,0 +1,18 @@
+const posthtml = require('posthtml')
+const {get, isObject, isEmpty} = require('lodash')
+const mergeLonghand = require('posthtml-postcss-merge-longhand')
+
+module.exports = async (html, config = {}) => {
+  config = get(config, 'shorthandInlineCSS', [])
+  const posthtmlOptions = get(config, 'build.posthtml.options', {})
+
+  if (typeof config === 'boolean' && config) {
+    html = await posthtml([mergeLonghand()]).process(html, posthtmlOptions).then(result => result.html)
+  }
+
+  if (isObject(config) && !isEmpty(config)) {
+    html = await posthtml([mergeLonghand({tags: config})]).process(html, posthtmlOptions).then(result => result.html)
+  }
+
+  return html
+}


Test patch:
diff --git a/test/test-transformers.js b/test/test-transformers.js
index e31ee49..690b547 100644
--- a/test/test-transformers.js
+++ b/test/test-transformers.js
@@ -48,18 +48,10 @@ test('remove inline background-color (with tags)', async t => {
 })
 
 test('inline CSS', async t => {
-  const html = `<div class="foo bar px-2 py-2">test</div>`
+  const html = `<div class="foo bar">test</div>`
   const css = `
     .foo {color: red}
     .bar {cursor: pointer}
-    .px-2 {
-      padding-left: 2px;
-      padding-right: 2px;
-    }
-    .py-2 {
-      padding-top: 2px;
-      padding-bottom: 2px;
-    }
   `
 
   const result = await Maizzle.inlineCSS(html, {
@@ -80,13 +72,7 @@ test('inline CSS', async t => {
     }
   })
 
-  const result2 = await Maizzle.inlineCSS(html, {
-    customCSS: css,
-    mergeLonghand: true
-  })
-
-  t.is(result, '<div class="foo bar px-2 py-2" style="color: red; padding: 2px;">test</div>')
-  t.is(result2, '<div class="foo bar px-2 py-2" style="color: red; cursor: pointer; padding: 2px;">test</div>')
+  t.is(result, '<div class="foo bar" style="color: red;">test</div>')
 })
 
 test('inline CSS (disabled)', async t => {
@@ -493,3 +479,32 @@ test('remove inlined selectors (disabled)', async t => {
 
   t.is(result, expected)
 })
+
+test('shorthand inline css', async t => {
+  const html = `
+    <div style="padding-left: 2px; padding-right: 2px; padding-top: 2px; padding-bottom: 2px;">padding</div>
+    <div style="margin-left: 2px; margin-right: 2px; margin-top: 2px; margin-bottom: 2px;">margin</div>
+    <div style="border-width: 1px; border-style: solid; border-color: #000;">border</div>
+    <p style="border-width: 1px; border-style: solid; border-color: #000;">border</p>
+  `
+
+  const expect = `
+    <div style="padding: 2px;">padding</div>
+    <div style="margin: 2px;">margin</div>
+    <div style="border: 1px solid #000;">border</div>
+    <p style="border-width: 1px; border-style: solid; border-color: #000;">border</p>
+  `
+
+  const expect2 = `
+    <div style="padding: 2px;">padding</div>
+    <div style="margin: 2px;">margin</div>
+    <div style="border: 1px solid #000;">border</div>
+    <p style="border: 1px solid #000;">border</p>
+  `
+
+  const result = await Maizzle.shorthandInlineCSS(html, {shorthandInlineCSS: ['div']})
+  const result2 = await Maizzle.shorthandInlineCSS(html, {shorthandInlineCSS: true})
+
+  t.is(result, expect)
+  t.is(result2, expect2)
+})