-
Notifications
You must be signed in to change notification settings - Fork 16
/
index.js
106 lines (89 loc) · 2.53 KB
/
index.js
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
'use strict'
const Module = require('module')
var BOOL_PROPS = [
'autofocus', 'checked', 'defaultchecked', 'disabled', 'formnovalidate',
'indeterminate', 'readonly', 'required', 'selected', 'willvalidate'
]
var BOOL_PROP_PATTERN = new RegExp(' (' + BOOL_PROPS.join('|') + '|onclick)=(""|\'\')', 'ig')
var DISABLED_PATTERN = new RegExp('disabled=("true"|\'true\')', 'ig')
const replaceMap = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
'\'': '''
}
const replaceMapRE = new RegExp(Object.keys(replaceMap).join('|'), 'g')
function replaceMapper (matched){
return replaceMap[matched]
}
function escape (value) {
return value.toString().replace(replaceMapRE, replaceMapper)
}
function handleValue (value) {
if (value === null || value === undefined || value === false) {
return ''
}
if (Array.isArray(value)) {
// Suppose that each item is a result of html``.
return value.join('')
}
// Ignore event handlers.
// onclick=${(e) => doSomething(e)}
// will become
// onclick=""
const valueType = typeof value
if (valueType === 'function') {
return ''
}
if (valueType === 'object' && value.constructor.name !== 'String') {
return objToString(value)
}
if (value.__encoded) {
return value
}
return escape(value)
}
function stringify () {
var pieces = arguments[0]
var output = ''
for (var i = 0; i < pieces.length - 1; i++) {
var piece = pieces[i]
var value = handleValue(arguments[i + 1])
if (piece[piece.length - 1] === '=') {
output += piece + '"' + value + '"'
} else {
output += piece + value
}
}
output += pieces[i]
output = output
.replace(DISABLED_PATTERN, 'disabled="disabled"')
.replace(BOOL_PROP_PATTERN, '')
// HACK: Avoid double encoding by marking encoded string
// You cannot add properties to string literals
// eslint-disable-next-line no-new-wrappers
const wrapper = new String(output)
wrapper.__encoded = true
return wrapper
}
function objToString (obj) {
var values = ''
const keys = Object.keys(obj)
for (var i = 0; i < keys.length - 1; i++) {
values += keys[i] + '="' + escape(obj[keys[i]] || '') + '" '
}
return values + keys[i] + '="' + escape(obj[keys[i]] || '') + '"'
}
function replace (moduleId) {
const originalRequire = Module.prototype.require
Module.prototype.require = function (id) {
if (id === moduleId) {
return stringify
} else {
return originalRequire.apply(this, arguments)
}
}
}
stringify.replace = replace
module.exports = stringify