Skip to content

Commit

Permalink
refactor: use posthtml-widows instead of string-remove-widows
Browse files Browse the repository at this point in the history
  • Loading branch information
cossssmin committed Nov 16, 2024
1 parent ba54c0b commit bccbd7b
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 135 deletions.
26 changes: 9 additions & 17 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
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@
"posthtml-render": "^3.0.0",
"posthtml-safe-class-names": "^4.1.0",
"posthtml-url-parameters": "^3.1.0",
"posthtml-widows": "^1.0.0",
"pretty": "^2.0.0",
"string-remove-widows": "^4.0.22",
"string-strip-html": "^13.4.8",
"tailwindcss": "^3.4.13",
"ws": "^8.18.0"
Expand Down
24 changes: 12 additions & 12 deletions src/transformers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,35 +218,35 @@ export async function run(html = '', config = {}) {
posthtmlPlugins.push(templateTag())

/**
* 17. Prettify
* 17. Replace strings
*
* Pretty-print HTML using js-beautify.
* Replace strings through regular expressions.
*/
if (get(config, 'prettify')) {
if (get(config, 'replaceStrings')) {
posthtmlPlugins.push(
prettify(get(config, 'prettify', {}))
replaceStrings(get(config, 'replaceStrings', {}))
)
}

/**
* 18. Minify
* 18. Prettify
*
* Minify HTML using html-crush.
* Pretty-print HTML using js-beautify.
*/
if (get(config, 'minify')) {
if (get(config, 'prettify')) {
posthtmlPlugins.push(
minify(get(config, 'minify', {}))
prettify(get(config, 'prettify', {}))
)
}

/**
* 19. Replace strings
* 19. Minify
*
* Replace strings through regular expressions.
* Minify HTML using html-crush.
*/
if (get(config, 'replaceStrings')) {
if (get(config, 'minify')) {
posthtmlPlugins.push(
replaceStrings(get(config, 'replaceStrings', {}))
minify(get(config, 'minify', {}))
)
}

Expand Down
79 changes: 15 additions & 64 deletions src/transformers/preventWidows.js
Original file line number Diff line number Diff line change
@@ -1,86 +1,37 @@
import posthtml from 'posthtml'
import posthtmlWidows from 'posthtml-widows'
import { defu as merge } from 'defu'
import { removeWidows } from 'string-remove-widows'

const posthtmlPlugin = (options = {}) => tree => {
export default function posthtmlPlugin(options = {}) {
options = merge(options, {
minWordCount: 3,
attrName: 'no-widows'
minWords: 3
})

// Ignore defaults
// Custom ignores
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: ']>'
start: '<!--[',
end: ']>'
},
// <![endif]-->
{
heads: '<![',
tails: ']--><'
start: '<![',
end: ']--><'
}
]

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

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

const process = node => {
if (node.attrs && Object.keys(node.attrs).includes(options.attrName)) {
const widowsRemovedString = removeWidows(tree.render(node.content), options).res
node.content = tree.render(tree.parser(widowsRemovedString))
delete node.attrs[options.attrName]
}

return node
options.ignore = options.ignore.concat(mappings)
}

return tree.walk(process)
return posthtmlWidows(options)
}

export default posthtmlPlugin

export async function preventWidows(html = '', options = {}, posthtmlOptions = {}) {
// Apply only to elements that contain the `prevent-widows` attribute
if (options.withAttributes) {
return posthtml([
posthtmlPlugin(options)
])
.process(html, posthtmlOptions)
.then(result => result.html)
}

// Apply to all elements
return removeWidows(html, options).res
return posthtml([
posthtmlPlugin(options)
])
.process(html, posthtmlOptions)
.then(result => result.html)
}
13 changes: 8 additions & 5 deletions test/transformers/widowWords.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@ import { preventWidows } from '../../src/index.js'

describe.concurrent('Widow words', () => {
test('Prevents widow words', async () => {
const result = await preventWidows('one two', { minWordCount: 2 })
const result = await preventWidows('<p no-widows>one two</p>', { minWords: 2 })

expect(result).toBe('one&nbsp;two')
expect(result).toBe('<p>one&nbsp;two</p>')
})

test('Ignores strings inside expressions', async () => {
const result = await preventWidows('<div no-widows>{{{ one two three }}}</div>', {
ignore: [
{ heads: '{{{', tails: '}}}' }
],
withAttributes: true
{ start: '{{{', end: '}}}' }
]
})

expect(result).toBe('<div>{{{ one two three }}}</div>')
Expand All @@ -24,4 +23,8 @@ describe.concurrent('Widow words', () => {

expect(result).toBe('<p>one two&nbsp;three</p><p>4 5 6</p>')
})

test('Ignores MSO comments', async () => {
expect(await preventWidows('<!--[if mso]>one two three<![endif]-->')).toBe('<!--[if mso]>one two three<![endif]-->')
})
})
52 changes: 16 additions & 36 deletions types/widowWords.d.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,38 @@
import type { Opts } from 'string-remove-widows';

export default interface WidowWordsConfig {
/**
The attribute name to use.
@default 'prevent-widows'
@default ['prevent-widows', 'no-widows']
*/
attrName?: string;
attributes?: Array<string>;

/**
Replace all widow word `nbsp;` instances with a single space.
This is basically the opposite of preventing widow words.
@default false
*/
removeWidowPreventionMeasures?: Opts['removeWidowPreventionMeasures'];

/**
Convert the space entity to the `targetLanguage`.
@default true
*/
convertEntities?: Opts['convertEntities'];

/**
Language to encode non-breaking spaces in.
@default 'html'
*/
targetLanguage?: Opts['targetLanguage'];

/**
Should whitespace in front of dashes (-), n-dashes (–) or m-dashes (—) be replaced with a `&nbsp;`.
@default true
*/
hyphens?: Opts['hyphens'];
createWidows?: Boolean;

/**
The minimum amount of words in a target string, in order to trigger the transformer.
@default 3
*/
minWordCount?: Opts['minWordCount'];

/**
The minimum amount non-whitespace characters in a target string, in order to trigger the transformer.
@default 20
*/
minCharCount?: Opts['minCharCount'];
minWords?: Number;

/**
Start/end pairs of strings that will prevent the transformer from removing widow words inside them.
*/
ignore?: Opts['ignore'];
@default [
{ start: '{{', end: '}}' }, // Handlebars, Liquid, Nunjucks, Twig, Jinja2, Mustache
{ start: '{%', end: '%}' }, // Liquid, Nunjucks, Twig, Jinja2
{ start: '<%=', end: '%>' }, // EJS, ERB
{ start: '<%', end: '%>' }, // EJS, ERB
{ start: '{$', end: '}' }, // Smarty
{ start: '<\\?', end: '\\?>' }, // PHP
{ start: '#{', end: '}' } // Pug
]
*/
ignore?: Array<{ start: string; end: string }>;
}

0 comments on commit bccbd7b

Please sign in to comment.