Skip to content

Commit

Permalink
Merge pull request #788 from maizzle/refactor-widow-words
Browse files Browse the repository at this point in the history
  • Loading branch information
cossssmin committed Oct 9, 2022
2 parents df27802 + 4035533 commit 49c2129
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 22 deletions.
36 changes: 25 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -69,8 +69,8 @@
"posthtml-safe-class-names": "^1.0.8",
"posthtml-url-parameters": "^1.0.4",
"pretty": "^2.0.0",
"prevent-widows": "^1.0.2",
"query-string": "^7.1.0",
"string-remove-widows": "^2.1.0",
"string-strip-html": "^8.2.0",
"tailwindcss": "^3.1.0"
},
Expand Down
2 changes: 1 addition & 1 deletion src/transformers/index.js
Expand Up @@ -49,7 +49,7 @@ exports.prettify = (html, config) => prettify(html, config, true)
exports.ensureSixHEX = (html, config) => ensureSixHEX(html, config)
exports.withFilters = (html, config) => filters(html, config, true)
exports.addURLParams = (html, config) => addURLParams(html, config, true)
exports.preventWidows = (html, config) => preventWidows(html, config, true)
exports.preventWidows = (html, config) => preventWidows(html, config)
exports.replaceStrings = (html, config) => replaceStrings(html, config, true)
exports.safeClassNames = (html, config) => safeClassNames(html, config, true)
exports.removeUnusedCSS = (html, config) => removeUnusedCSS(html, config, true)
Expand Down
81 changes: 74 additions & 7 deletions src/transformers/preventWidows.js
@@ -1,13 +1,80 @@
const {get} = require('lodash')
const posthtml = require('posthtml')
const preventWidows = require('prevent-widows')
const {get, isEmpty} = require('lodash')
const {removeWidows} = require('string-remove-widows')

module.exports = async (html, config = {}, direct = false) => {
const posthtmlOptions = get(config, 'build.posthtml.options', {})
module.exports = async (html, config = {}) => {
if (isEmpty(config)) {
return removeWidows(html).res
}

const posthtmlOptions = get(config, 'build.posthtml.options', {recognizeNoValueAttribute: true})

return posthtml([removeWidowsPlugin(config)]).process(html, posthtmlOptions).then(result => result.html)
}

const removeWidowsPlugin = options => tree => {
const {attrName = 'prevent-widows', ...removeWidowsOptions} = get(options, 'widowWords', options)

removeWidowsOptions.minWordCount = removeWidowsOptions.minWordCount || 3

// Ignore defaults
const mappings = [
// Jinja-like
{
heads: '{{',
tails: '}}'
},
{
heads: ['{% if', '{%- if'],
tails: ['{% endif', '{%- endif']
},
{
heads: ['{% for', '{%- for'],
tails: ['{% endfor', '{%- endfor']
},
{
heads: ['{%', '{%-'],
tails: ['%}', '-%}']
},
{
heads: '{#',
tails: '#}'
},
// ASP/Hexo-like
{
heads: ['<%', '<%=', '<%-'],
tails: ['%>', '=%>', '-%>']
},
// MSO comments
{
heads: '<!--[',
tails: ']>'
},
// <![endif]-->
{
heads: '<![',
tails: ']--><'
}
]

if (Array.isArray(removeWidowsOptions.ignore)) {
removeWidowsOptions.ignore.forEach(pair => mappings.push(pair))
}

if (typeof removeWidowsOptions.ignore !== 'string') {
removeWidowsOptions.ignore = mappings
}

const process = node => {
if (node.attrs && Object.keys(node.attrs).includes(attrName)) {
const widowsRemovedString = removeWidows(tree.render(node.content), removeWidowsOptions).res

node.content = tree.render(tree.parser(widowsRemovedString))
node.attrs[attrName] = false
}

if (direct) {
return preventWidows(html)
return node
}

return posthtml([preventWidows.posthtml()]).process(html, posthtmlOptions).then(result => result.html)
return tree.walk(process)
}
57 changes: 55 additions & 2 deletions test/test-transformers.js
Expand Up @@ -373,9 +373,62 @@ test('attribute to style', async t => {
})

test('prevent widows', async t => {
const html = await Maizzle.preventWidows('lorem ipsum dolor')
const html = await Maizzle.preventWidows(`
<!--[if mso]>
<p>A paragraph inside an Outlook MSO comment</p>
<![endif]-->
<div>Text following an MSO comment</div>
`)

t.is(html, `
<!--[if mso]>
<p>A paragraph inside an Outlook MSO&nbsp;comment</p>
<![endif]-->
<div>Text following an MSO&nbsp;comment</div>
`)
})

test('prevent widows (with options)', async t => {
const html = await Maizzle.preventWidows(`
<div no-widows>
<p>Text following an MSO comment</p>
<!--[if mso 15]>
<p>A paragraph inside an Outlook MSO comment</p>
<p>unescaped {{{ foo }}}</p>
<![endif]-->
<p>expression {{ foo }}</p>
<!--[if !mso]><!-->
<div>All Outlooks will ignore this</div>
<!--<![endif]-->
<p>unescaped {{{ foo }}}</p>
</div>
<p>Should not remove widows here</p>
`, {
attrName: 'no-widows',
minWordCount: 3,
ignore: [
{
heads: 'foo',
tails: 'bar'
}
]
})

t.is(html, 'lorem ipsum&nbsp;dolor')
t.is(html, `
<div>
<p>Text following an MSO&nbsp;comment</p>
<!--[if mso 15]>
<p>A paragraph inside an Outlook MSO&nbsp;comment</p>
<p>unescaped {{{ foo }}}</p>
<![endif]-->
<p>expression {{ foo }}</p>
<!--[if !mso]><!-->
<div>All Outlooks will ignore this</div>
<!--<![endif]-->
<p>unescaped {{{ foo }}}</p>
</div>
<p>Should not remove widows here</p>
`)
})

test('markdown (disabled)', async t => {
Expand Down

0 comments on commit 49c2129

Please sign in to comment.