Skip to content

Commit

Permalink
Added escapeHtml method to string package
Browse files Browse the repository at this point in the history
refs https://github.com/TryGhost/Team/issues/1871

This method is required in a couple of places where we want to escape HTML manually, such as the email template.
  • Loading branch information
SimonBackx committed Sep 6, 2022
1 parent 6082ff4 commit 4a605f5
Show file tree
Hide file tree
Showing 5 changed files with 357 additions and 6 deletions.
18 changes: 18 additions & 0 deletions packages/string/lib/escapeHtml.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* escapeHTML
*
* Escape a string to be used as text or an attribute in HTML
*
* @param {string} string - the string we want to escape
* @returns {string} The escaped string
*/
module.exports = function (string) {
const htmlChars = {
'&': '&',
'"': '"',
'\'': ''',
'<': '&lt;',
'>': '&gt;'
};
return string.replace(/[&"'<>]/g, c => htmlChars[c]);
};
1 change: 1 addition & 0 deletions packages/string/lib/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
module.exports.stripInvisibleChars = require('./stripInvisibleChars');
module.exports.slugify = require('./slugify');
module.exports.escapeHtml = require('./escapeHtml');
1 change: 1 addition & 0 deletions packages/string/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
},
"devDependencies": {
"c8": "7.12.0",
"jsdom": "^20.0.0",
"mocha": "10.0.0",
"should": "13.2.3",
"sinon": "14.0.0"
Expand Down
44 changes: 44 additions & 0 deletions packages/string/test/escapeHtml.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
require('./utils');

const escapeHtml = require('../lib').escapeHtml;
const jsdom = require('jsdom');

describe('Escape HTML', function () {
it('escapes all characters', function () {
const result = escapeHtml(`<tag>"Black" & 'White'</tag>`);
result.should.equal(`&lt;tag&gt;&quot;Black&quot; &amp; &apos;White&apos;&lt;/tag&gt;`);
});

it('produces valid HTML attributes', function () {
const myAttribute = `><tag>"Black" & 'White'</tag>`;
const htmls = [
`<input value="${escapeHtml(myAttribute)}" type="text" />`,
`<input value='${escapeHtml(myAttribute)}' type='text' />`
];

for (const html of htmls) {
const dom = new jsdom.JSDOM(html);
should(dom.window.document.querySelector('input').getAttribute('value')).equal(myAttribute);
should(dom.window.document.querySelector('input').value).equal(myAttribute);
}
});

it('produces valid HTML text', function () {
const texts = [
`<tag>"Black" & 'White'</tag>`,
`<![CDATA[This is no data]]>`,
`<!--This is no comment-->`,
`</p>This doesn't end<p>`
];
const htmls = texts.map(text => [
`<p>${escapeHtml(text)}</p>`
]);

for (const [index, html] of htmls.entries()) {
const text = texts[index];
const dom = new jsdom.JSDOM(html);
should(dom.window.document.querySelector('p').textContent).equal(text);
should(dom.window.document.querySelector('p').innerHTML).not.equal(text);
}
});
});
Loading

0 comments on commit 4a605f5

Please sign in to comment.