forked from Janpot/escape-html-template-tag
-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.mjs
50 lines (40 loc) · 1.49 KB
/
index.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
const CHARACTER_REPLACEMENT_MAP = {
'<': '<',
'>': '>',
'&': '&',
'"': '"',
"'": '''
}
const HTML_UNSAFE_CHARACTERS_REGEX = /<|>|&|"|'/g
const ATTRIBUTE_UNSAFE_CHARACTERS_REGEX = /"|'/g
const WHITESPACE_REGEX = '[\\n\\r\\t]*'
const MALICIOUS_PROTOCOL_REGEX = new RegExp(Array.from('javascript:', (char) => `${char}${WHITESPACE_REGEX}`).join(''), 'ig')
const $getReplacementString = char => CHARACTER_REPLACEMENT_MAP[char]
const sanitizeAttributeValue = value => value
.replace(ATTRIBUTE_UNSAFE_CHARACTERS_REGEX, $getReplacementString)
.replace(MALICIOUS_PROTOCOL_REGEX, '')
class HtmlSafeString {
constructor (parts, subs) {
this.$ = parts[0]
for (let i = 0; i < subs.length; i++) {
const sub = subs[i]
if (Array.isArray(sub)) for (let j = 0; j < sub.length; j++) this.$esc(sub[j])
else this.$esc(sub)
this.$ += parts[i + 1]
}
}
$esc (sub) {
this.$ += sub instanceof HtmlSafeString ? sub.$ : String(sub).replace(HTML_UNSAFE_CHARACTERS_REGEX, $getReplacementString)
}
toString () {
return this.$
}
}
const join = (subs, separator = ',') => subs.length
? new HtmlSafeString(['', ...new Array(subs.length - 1).fill(separator), ''], subs)
: ''
const safe = value => new HtmlSafeString([String(value)], [])
const safeAttribute = value => new HtmlSafeString([sanitizeAttributeValue(String(value))], [])
const html = (parts, ...subs) => new HtmlSafeString(parts, subs)
export default html
export { join, safe, safeAttribute }