@touchvue/chat 1.0.0-beta.51 → 1.0.0-beta.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -70
- package/es/node_modules/.pnpm/{dompurify@3.4.3 → dompurify@3.3.0}/node_modules/dompurify/dist/purify.es.mjs +143 -299
- package/es/node_modules/.pnpm/dompurify@3.3.0/node_modules/dompurify/dist/purify.es.mjs.map +1 -0
- package/es/package.json.css +1 -1
- package/es/package.json.mjs +1 -1
- package/es/packages/components/resolver.mjs.map +1 -1
- package/es/packages/components/touchchat/component/AiRobot/HelloChat.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/component/AiRobot/letter.vue.mjs +1 -1
- package/es/packages/components/touchchat/component/AiRobot/letter.vue2.mjs +9 -9
- package/es/packages/components/touchchat/component/AiRobot/letter.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/component/FileContent.vue2.mjs +3 -3
- package/es/packages/components/touchchat/component/FileContent.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/component/FileView.vue2.mjs +2 -2
- package/es/packages/components/touchchat/component/FileView.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/component/HelloChat.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/component/ImageFile.vue2.mjs +6 -6
- package/es/packages/components/touchchat/component/ImageFile.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/component/ImageView.vue2.mjs +1 -1
- package/es/packages/components/touchchat/component/ImageView.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/component/LinkView.vue2.mjs +4 -4
- package/es/packages/components/touchchat/component/LinkView.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/component/MarkLayer.vue2.mjs +1 -1
- package/es/packages/components/touchchat/component/MarkLayer.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/component/ModuleSelect.vue2.mjs +2 -2
- package/es/packages/components/touchchat/component/ModuleSelect.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/component/PDFFile.vue2.mjs +10 -10
- package/es/packages/components/touchchat/component/PDFFile.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/component/QuoteContent.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/component/RealtimeVoice.vue2.mjs +1 -1
- package/es/packages/components/touchchat/component/RealtimeVoice.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/component/UploadView.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/component/VideoFile.vue.mjs +1 -1
- package/es/packages/components/touchchat/component/VideoFile.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/AgentsView.vue2.mjs +1 -1
- package/es/packages/components/touchchat/src/AiChat/AgentsView.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/AiMessage.vue2.mjs +30 -30
- package/es/packages/components/touchchat/src/AiChat/AiMessage.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/Chat/scriptMatcher.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/Chat/types.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/Chat/useChat.mjs +6 -0
- package/es/packages/components/touchchat/src/AiChat/Chat/useChat.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/Chat/useCopy.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/Chat/useMessageRender.mjs +1 -1
- package/es/packages/components/touchchat/src/AiChat/Chat/useMessageRender.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/Chat/useSSE.mjs +93 -4
- package/es/packages/components/touchchat/src/AiChat/Chat/useSSE.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/ChatInput.vue2.mjs +5 -5
- package/es/packages/components/touchchat/src/AiChat/ChatInput.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/HistoryList.vue2.mjs +1 -1
- package/es/packages/components/touchchat/src/AiChat/HistoryList.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/HistorySidebar.vue2.mjs +3 -3
- package/es/packages/components/touchchat/src/AiChat/HistorySidebar.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/MessageActions.vue2.mjs +11 -11
- package/es/packages/components/touchchat/src/AiChat/MessageActions.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/SiderBarView.vue2.mjs +3 -3
- package/es/packages/components/touchchat/src/AiChat/SiderBarView.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/TouchAgent.vue2.mjs +1 -1
- package/es/packages/components/touchchat/src/AiChat/TouchChat.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/TouchHistory.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/UserMessage.vue2.mjs +16 -16
- package/es/packages/components/touchchat/src/AiChat/UserMessage.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/src/index.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/utils/a2aService.mjs.map +1 -1
- package/es/packages/components/touchchat/utils/fetchStream.mjs.map +1 -1
- package/es/packages/components/touchchat/utils/markdown.mjs +1 -1
- package/lib/node_modules/.pnpm/{dompurify@3.4.3 → dompurify@3.3.0}/node_modules/dompurify/dist/purify.es.js +143 -299
- package/lib/node_modules/.pnpm/dompurify@3.3.0/node_modules/dompurify/dist/purify.es.js.map +1 -0
- package/lib/package.json.css +1 -1
- package/lib/package.json.js +1 -1
- package/lib/packages/components/resolver.js.map +1 -1
- package/lib/packages/components/touchchat/component/AiRobot/HelloChat.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/component/AiRobot/letter.vue.js +1 -1
- package/lib/packages/components/touchchat/component/AiRobot/letter.vue2.js +9 -9
- package/lib/packages/components/touchchat/component/AiRobot/letter.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/component/FileContent.vue2.js +3 -3
- package/lib/packages/components/touchchat/component/FileContent.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/component/FileView.vue2.js +2 -2
- package/lib/packages/components/touchchat/component/FileView.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/component/HelloChat.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/component/ImageFile.vue2.js +6 -6
- package/lib/packages/components/touchchat/component/ImageFile.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/component/ImageView.vue2.js +1 -1
- package/lib/packages/components/touchchat/component/ImageView.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/component/LinkView.vue2.js +4 -4
- package/lib/packages/components/touchchat/component/LinkView.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/component/MarkLayer.vue2.js +1 -1
- package/lib/packages/components/touchchat/component/MarkLayer.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/component/ModuleSelect.vue2.js +2 -2
- package/lib/packages/components/touchchat/component/ModuleSelect.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/component/PDFFile.vue2.js +10 -10
- package/lib/packages/components/touchchat/component/PDFFile.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/component/QuoteContent.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/component/RealtimeVoice.vue2.js +1 -1
- package/lib/packages/components/touchchat/component/RealtimeVoice.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/component/UploadView.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/component/VideoFile.vue.js +1 -1
- package/lib/packages/components/touchchat/component/VideoFile.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/AgentsView.vue2.js +1 -1
- package/lib/packages/components/touchchat/src/AiChat/AgentsView.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/AiMessage.vue2.js +30 -30
- package/lib/packages/components/touchchat/src/AiChat/AiMessage.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/Chat/scriptMatcher.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/Chat/types.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/Chat/useChat.js +6 -0
- package/lib/packages/components/touchchat/src/AiChat/Chat/useChat.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/Chat/useCopy.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/Chat/useMessageRender.js +1 -1
- package/lib/packages/components/touchchat/src/AiChat/Chat/useMessageRender.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/Chat/useSSE.js +93 -4
- package/lib/packages/components/touchchat/src/AiChat/Chat/useSSE.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/ChatInput.vue2.js +5 -5
- package/lib/packages/components/touchchat/src/AiChat/ChatInput.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/HistoryList.vue2.js +1 -1
- package/lib/packages/components/touchchat/src/AiChat/HistoryList.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/HistorySidebar.vue2.js +3 -3
- package/lib/packages/components/touchchat/src/AiChat/HistorySidebar.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/MessageActions.vue2.js +11 -11
- package/lib/packages/components/touchchat/src/AiChat/MessageActions.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/SiderBarView.vue2.js +3 -3
- package/lib/packages/components/touchchat/src/AiChat/SiderBarView.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/TouchAgent.vue2.js +1 -1
- package/lib/packages/components/touchchat/src/AiChat/TouchChat.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/TouchHistory.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/UserMessage.vue2.js +16 -16
- package/lib/packages/components/touchchat/src/AiChat/UserMessage.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/src/index.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/utils/a2aService.js.map +1 -1
- package/lib/packages/components/touchchat/utils/fetchStream.js.map +1 -1
- package/lib/packages/components/touchchat/utils/markdown.js +1 -1
- package/package.json +83 -83
- package/es/node_modules/.pnpm/dompurify@3.4.3/node_modules/dompurify/dist/purify.es.mjs.map +0 -1
- package/lib/node_modules/.pnpm/dompurify@3.4.3/node_modules/dompurify/dist/purify.es.js.map +0 -1
|
@@ -1,62 +1,21 @@
|
|
|
1
|
-
/*! @license DOMPurify 3.
|
|
1
|
+
/*! @license DOMPurify 3.3.0 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.3.0/LICENSE */
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
f = true,
|
|
20
|
-
o = false;
|
|
21
|
-
try {
|
|
22
|
-
if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
|
|
23
|
-
} catch (r) {
|
|
24
|
-
o = true, n = r;
|
|
25
|
-
} finally {
|
|
26
|
-
try {
|
|
27
|
-
if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
|
|
28
|
-
} finally {
|
|
29
|
-
if (o) throw n;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return a;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
function _nonIterableRest() {
|
|
36
|
-
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
37
|
-
}
|
|
38
|
-
function _slicedToArray(r, e) {
|
|
39
|
-
return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
|
|
40
|
-
}
|
|
41
|
-
function _unsupportedIterableToArray(r, a) {
|
|
42
|
-
if (r) {
|
|
43
|
-
if ("string" == typeof r) return _arrayLikeToArray(r, a);
|
|
44
|
-
var t = {}.toString.call(r).slice(8, -1);
|
|
45
|
-
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const entries = Object.entries,
|
|
50
|
-
setPrototypeOf = Object.setPrototypeOf,
|
|
51
|
-
isFrozen = Object.isFrozen,
|
|
52
|
-
getPrototypeOf = Object.getPrototypeOf,
|
|
53
|
-
getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
|
|
54
|
-
let freeze = Object.freeze,
|
|
55
|
-
seal = Object.seal,
|
|
56
|
-
create = Object.create; // eslint-disable-line import/no-mutable-exports
|
|
57
|
-
let _ref = typeof Reflect !== 'undefined' && Reflect,
|
|
58
|
-
apply = _ref.apply,
|
|
59
|
-
construct = _ref.construct;
|
|
3
|
+
const {
|
|
4
|
+
entries,
|
|
5
|
+
setPrototypeOf,
|
|
6
|
+
isFrozen,
|
|
7
|
+
getPrototypeOf,
|
|
8
|
+
getOwnPropertyDescriptor
|
|
9
|
+
} = Object;
|
|
10
|
+
let {
|
|
11
|
+
freeze,
|
|
12
|
+
seal,
|
|
13
|
+
create
|
|
14
|
+
} = Object; // eslint-disable-line import/no-mutable-exports
|
|
15
|
+
let {
|
|
16
|
+
apply,
|
|
17
|
+
construct
|
|
18
|
+
} = typeof Reflect !== 'undefined' && Reflect;
|
|
60
19
|
if (!freeze) {
|
|
61
20
|
freeze = function freeze(x) {
|
|
62
21
|
return x;
|
|
@@ -88,19 +47,13 @@ const arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);
|
|
|
88
47
|
const arrayPop = unapply(Array.prototype.pop);
|
|
89
48
|
const arrayPush = unapply(Array.prototype.push);
|
|
90
49
|
const arraySplice = unapply(Array.prototype.splice);
|
|
91
|
-
const arrayIsArray = Array.isArray;
|
|
92
50
|
const stringToLowerCase = unapply(String.prototype.toLowerCase);
|
|
93
51
|
const stringToString = unapply(String.prototype.toString);
|
|
94
52
|
const stringMatch = unapply(String.prototype.match);
|
|
95
53
|
const stringReplace = unapply(String.prototype.replace);
|
|
96
54
|
const stringIndexOf = unapply(String.prototype.indexOf);
|
|
97
55
|
const stringTrim = unapply(String.prototype.trim);
|
|
98
|
-
const numberToString = unapply(Number.prototype.toString);
|
|
99
|
-
const booleanToString = unapply(Boolean.prototype.toString);
|
|
100
|
-
const bigintToString = typeof BigInt === 'undefined' ? null : unapply(BigInt.prototype.toString);
|
|
101
|
-
const symbolToString = typeof Symbol === 'undefined' ? null : unapply(Symbol.prototype.toString);
|
|
102
56
|
const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
|
|
103
|
-
const objectToString = unapply(Object.prototype.toString);
|
|
104
57
|
const regExpTest = unapply(RegExp.prototype.test);
|
|
105
58
|
const typeErrorCreate = unconstruct(TypeError);
|
|
106
59
|
/**
|
|
@@ -150,9 +103,6 @@ function addToSet(set, array) {
|
|
|
150
103
|
// Prevent prototype setters from intercepting set as a this value.
|
|
151
104
|
setPrototypeOf(set, null);
|
|
152
105
|
}
|
|
153
|
-
if (!arrayIsArray(array)) {
|
|
154
|
-
return set;
|
|
155
|
-
}
|
|
156
106
|
let l = array.length;
|
|
157
107
|
while (l--) {
|
|
158
108
|
let element = array[l];
|
|
@@ -193,13 +143,10 @@ function cleanArray(array) {
|
|
|
193
143
|
*/
|
|
194
144
|
function clone(object) {
|
|
195
145
|
const newObject = create(null);
|
|
196
|
-
for (const
|
|
197
|
-
var _ref3 = _slicedToArray(_ref2, 2);
|
|
198
|
-
const property = _ref3[0];
|
|
199
|
-
const value = _ref3[1];
|
|
146
|
+
for (const [property, value] of entries(object)) {
|
|
200
147
|
const isPropertyExist = objectHasOwnProperty(object, property);
|
|
201
148
|
if (isPropertyExist) {
|
|
202
|
-
if (
|
|
149
|
+
if (Array.isArray(value)) {
|
|
203
150
|
newObject[property] = cleanArray(value);
|
|
204
151
|
} else if (value && typeof value === 'object' && value.constructor === Object) {
|
|
205
152
|
newObject[property] = clone(value);
|
|
@@ -210,58 +157,6 @@ function clone(object) {
|
|
|
210
157
|
}
|
|
211
158
|
return newObject;
|
|
212
159
|
}
|
|
213
|
-
/**
|
|
214
|
-
* Convert non-node values into strings without depending on direct property access.
|
|
215
|
-
*
|
|
216
|
-
* @param value - The value to stringify.
|
|
217
|
-
* @returns A string representation of the provided value.
|
|
218
|
-
*/
|
|
219
|
-
function stringifyValue(value) {
|
|
220
|
-
switch (typeof value) {
|
|
221
|
-
case 'string':
|
|
222
|
-
{
|
|
223
|
-
return value;
|
|
224
|
-
}
|
|
225
|
-
case 'number':
|
|
226
|
-
{
|
|
227
|
-
return numberToString(value);
|
|
228
|
-
}
|
|
229
|
-
case 'boolean':
|
|
230
|
-
{
|
|
231
|
-
return booleanToString(value);
|
|
232
|
-
}
|
|
233
|
-
case 'bigint':
|
|
234
|
-
{
|
|
235
|
-
return bigintToString ? bigintToString(value) : '0';
|
|
236
|
-
}
|
|
237
|
-
case 'symbol':
|
|
238
|
-
{
|
|
239
|
-
return symbolToString ? symbolToString(value) : 'Symbol()';
|
|
240
|
-
}
|
|
241
|
-
case 'undefined':
|
|
242
|
-
{
|
|
243
|
-
return objectToString(value);
|
|
244
|
-
}
|
|
245
|
-
case 'function':
|
|
246
|
-
case 'object':
|
|
247
|
-
{
|
|
248
|
-
if (value === null) {
|
|
249
|
-
return objectToString(value);
|
|
250
|
-
}
|
|
251
|
-
const valueAsRecord = value;
|
|
252
|
-
const valueToString = lookupGetter(valueAsRecord, 'toString');
|
|
253
|
-
if (typeof valueToString === 'function') {
|
|
254
|
-
const stringified = valueToString(valueAsRecord);
|
|
255
|
-
return typeof stringified === 'string' ? stringified : objectToString(stringified);
|
|
256
|
-
}
|
|
257
|
-
return objectToString(value);
|
|
258
|
-
}
|
|
259
|
-
default:
|
|
260
|
-
{
|
|
261
|
-
return objectToString(value);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
160
|
/**
|
|
266
161
|
* This method automatically checks if the prop is function or getter and behaves accordingly.
|
|
267
162
|
*
|
|
@@ -287,14 +182,6 @@ function lookupGetter(object, prop) {
|
|
|
287
182
|
}
|
|
288
183
|
return fallbackValue;
|
|
289
184
|
}
|
|
290
|
-
function isRegex(value) {
|
|
291
|
-
try {
|
|
292
|
-
regExpTest(value, '');
|
|
293
|
-
return true;
|
|
294
|
-
} catch (_unused) {
|
|
295
|
-
return false;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
185
|
|
|
299
186
|
const html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'search', 'section', 'select', 'shadow', 'slot', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);
|
|
300
187
|
const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'enterkeyhint', 'exportparts', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'inputmode', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'part', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
|
|
@@ -310,14 +197,15 @@ const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mgly
|
|
|
310
197
|
const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
|
|
311
198
|
const text = freeze(['#text']);
|
|
312
199
|
|
|
313
|
-
const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns']);
|
|
200
|
+
const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns', 'slot']);
|
|
314
201
|
const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'mask-type', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
|
|
315
|
-
const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', '
|
|
202
|
+
const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
|
|
316
203
|
const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
|
|
317
204
|
|
|
318
|
-
|
|
319
|
-
const
|
|
320
|
-
const
|
|
205
|
+
// eslint-disable-next-line unicorn/better-regex
|
|
206
|
+
const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
|
|
207
|
+
const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
|
|
208
|
+
const TMPLIT_EXPR = seal(/\$\{[\w\W]*/gm); // eslint-disable-line unicorn/better-regex
|
|
321
209
|
const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
|
|
322
210
|
const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
|
|
323
211
|
const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
|
|
@@ -328,15 +216,38 @@ const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205
|
|
|
328
216
|
const DOCTYPE_NAME = seal(/^html$/i);
|
|
329
217
|
const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
|
|
330
218
|
|
|
219
|
+
var EXPRESSIONS = /*#__PURE__*/Object.freeze({
|
|
220
|
+
__proto__: null,
|
|
221
|
+
ARIA_ATTR: ARIA_ATTR,
|
|
222
|
+
ATTR_WHITESPACE: ATTR_WHITESPACE,
|
|
223
|
+
CUSTOM_ELEMENT: CUSTOM_ELEMENT,
|
|
224
|
+
DATA_ATTR: DATA_ATTR,
|
|
225
|
+
DOCTYPE_NAME: DOCTYPE_NAME,
|
|
226
|
+
ERB_EXPR: ERB_EXPR,
|
|
227
|
+
IS_ALLOWED_URI: IS_ALLOWED_URI,
|
|
228
|
+
IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
|
|
229
|
+
MUSTACHE_EXPR: MUSTACHE_EXPR,
|
|
230
|
+
TMPLIT_EXPR: TMPLIT_EXPR
|
|
231
|
+
});
|
|
232
|
+
|
|
331
233
|
/* eslint-disable @typescript-eslint/indent */
|
|
332
234
|
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
|
|
333
235
|
const NODE_TYPE = {
|
|
334
236
|
element: 1,
|
|
237
|
+
attribute: 2,
|
|
335
238
|
text: 3,
|
|
239
|
+
cdataSection: 4,
|
|
240
|
+
entityReference: 5,
|
|
241
|
+
// Deprecated
|
|
242
|
+
entityNode: 6,
|
|
336
243
|
// Deprecated
|
|
337
244
|
progressingInstruction: 7,
|
|
338
245
|
comment: 8,
|
|
339
|
-
document: 9
|
|
246
|
+
document: 9,
|
|
247
|
+
documentType: 10,
|
|
248
|
+
documentFragment: 11,
|
|
249
|
+
notation: 12 // Deprecated
|
|
250
|
+
};
|
|
340
251
|
const getGlobal = function getGlobal() {
|
|
341
252
|
return typeof window === 'undefined' ? null : window;
|
|
342
253
|
};
|
|
@@ -394,7 +305,7 @@ const _createHooksMap = function _createHooksMap() {
|
|
|
394
305
|
function createDOMPurify() {
|
|
395
306
|
let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
|
|
396
307
|
const DOMPurify = root => createDOMPurify(root);
|
|
397
|
-
DOMPurify.version = '3.
|
|
308
|
+
DOMPurify.version = '3.3.0';
|
|
398
309
|
DOMPurify.removed = [];
|
|
399
310
|
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
|
|
400
311
|
// Not running in a browser, provide a factory function
|
|
@@ -402,19 +313,22 @@ function createDOMPurify() {
|
|
|
402
313
|
DOMPurify.isSupported = false;
|
|
403
314
|
return DOMPurify;
|
|
404
315
|
}
|
|
405
|
-
let
|
|
316
|
+
let {
|
|
317
|
+
document
|
|
318
|
+
} = window;
|
|
406
319
|
const originalDocument = document;
|
|
407
320
|
const currentScript = originalDocument.currentScript;
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
NamedNodeMap =
|
|
415
|
-
HTMLFormElement
|
|
416
|
-
DOMParser
|
|
417
|
-
trustedTypes
|
|
321
|
+
const {
|
|
322
|
+
DocumentFragment,
|
|
323
|
+
HTMLTemplateElement,
|
|
324
|
+
Node,
|
|
325
|
+
Element,
|
|
326
|
+
NodeFilter,
|
|
327
|
+
NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,
|
|
328
|
+
HTMLFormElement,
|
|
329
|
+
DOMParser,
|
|
330
|
+
trustedTypes
|
|
331
|
+
} = window;
|
|
418
332
|
const ElementPrototype = Element.prototype;
|
|
419
333
|
const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
|
|
420
334
|
const remove = lookupGetter(ElementPrototype, 'remove');
|
|
@@ -435,26 +349,33 @@ function createDOMPurify() {
|
|
|
435
349
|
}
|
|
436
350
|
let trustedTypesPolicy;
|
|
437
351
|
let emptyHTML = '';
|
|
438
|
-
const
|
|
439
|
-
implementation
|
|
440
|
-
createNodeIterator
|
|
441
|
-
createDocumentFragment
|
|
442
|
-
getElementsByTagName
|
|
443
|
-
|
|
352
|
+
const {
|
|
353
|
+
implementation,
|
|
354
|
+
createNodeIterator,
|
|
355
|
+
createDocumentFragment,
|
|
356
|
+
getElementsByTagName
|
|
357
|
+
} = document;
|
|
358
|
+
const {
|
|
359
|
+
importNode
|
|
360
|
+
} = originalDocument;
|
|
444
361
|
let hooks = _createHooksMap();
|
|
445
362
|
/**
|
|
446
363
|
* Expose whether this browser supports running the full DOMPurify.
|
|
447
364
|
*/
|
|
448
365
|
DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
366
|
+
const {
|
|
367
|
+
MUSTACHE_EXPR,
|
|
368
|
+
ERB_EXPR,
|
|
369
|
+
TMPLIT_EXPR,
|
|
370
|
+
DATA_ATTR,
|
|
371
|
+
ARIA_ATTR,
|
|
372
|
+
IS_SCRIPT_OR_DATA,
|
|
373
|
+
ATTR_WHITESPACE,
|
|
374
|
+
CUSTOM_ELEMENT
|
|
375
|
+
} = EXPRESSIONS;
|
|
376
|
+
let {
|
|
377
|
+
IS_ALLOWED_URI: IS_ALLOWED_URI$1
|
|
378
|
+
} = EXPRESSIONS;
|
|
458
379
|
/**
|
|
459
380
|
* We consider the elements and attributes below to be safe. Ideally
|
|
460
381
|
* don't add any new ones but feel free to remove unwanted ones.
|
|
@@ -632,15 +553,15 @@ function createDOMPurify() {
|
|
|
632
553
|
// HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
|
|
633
554
|
transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
|
|
634
555
|
/* Set configuration parameters */
|
|
635
|
-
ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS')
|
|
636
|
-
ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR')
|
|
637
|
-
ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES')
|
|
638
|
-
URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR')
|
|
639
|
-
DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS')
|
|
640
|
-
FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS')
|
|
641
|
-
FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS')
|
|
642
|
-
FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR')
|
|
643
|
-
USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES
|
|
556
|
+
ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
|
|
557
|
+
ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
|
|
558
|
+
ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
|
|
559
|
+
URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES;
|
|
560
|
+
DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS;
|
|
561
|
+
FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
|
|
562
|
+
FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : clone({});
|
|
563
|
+
FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : clone({});
|
|
564
|
+
USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;
|
|
644
565
|
ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
|
|
645
566
|
ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
|
|
646
567
|
ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
|
|
@@ -656,20 +577,19 @@ function createDOMPurify() {
|
|
|
656
577
|
SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
|
|
657
578
|
KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
|
|
658
579
|
IN_PLACE = cfg.IN_PLACE || false; // Default false
|
|
659
|
-
IS_ALLOWED_URI$1 =
|
|
660
|
-
NAMESPACE =
|
|
661
|
-
MATHML_TEXT_INTEGRATION_POINTS =
|
|
662
|
-
HTML_INTEGRATION_POINTS =
|
|
663
|
-
|
|
664
|
-
CUSTOM_ELEMENT_HANDLING
|
|
665
|
-
|
|
666
|
-
CUSTOM_ELEMENT_HANDLING.tagNameCheck = customElementHandling.tagNameCheck; // Default undefined
|
|
580
|
+
IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
|
|
581
|
+
NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
|
|
582
|
+
MATHML_TEXT_INTEGRATION_POINTS = cfg.MATHML_TEXT_INTEGRATION_POINTS || MATHML_TEXT_INTEGRATION_POINTS;
|
|
583
|
+
HTML_INTEGRATION_POINTS = cfg.HTML_INTEGRATION_POINTS || HTML_INTEGRATION_POINTS;
|
|
584
|
+
CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
|
|
585
|
+
if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
|
|
586
|
+
CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
|
|
667
587
|
}
|
|
668
|
-
if (
|
|
669
|
-
CUSTOM_ELEMENT_HANDLING.attributeNameCheck =
|
|
588
|
+
if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
|
|
589
|
+
CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
|
|
670
590
|
}
|
|
671
|
-
if (
|
|
672
|
-
CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements =
|
|
591
|
+
if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
|
|
592
|
+
CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
|
|
673
593
|
}
|
|
674
594
|
if (SAFE_FOR_TEMPLATES) {
|
|
675
595
|
ALLOW_DATA_ATTR = false;
|
|
@@ -680,7 +600,7 @@ function createDOMPurify() {
|
|
|
680
600
|
/* Parse profile info */
|
|
681
601
|
if (USE_PROFILES) {
|
|
682
602
|
ALLOWED_TAGS = addToSet({}, text);
|
|
683
|
-
ALLOWED_ATTR =
|
|
603
|
+
ALLOWED_ATTR = [];
|
|
684
604
|
if (USE_PROFILES.html === true) {
|
|
685
605
|
addToSet(ALLOWED_TAGS, html$1);
|
|
686
606
|
addToSet(ALLOWED_ATTR, html);
|
|
@@ -701,46 +621,36 @@ function createDOMPurify() {
|
|
|
701
621
|
addToSet(ALLOWED_ATTR, xml);
|
|
702
622
|
}
|
|
703
623
|
}
|
|
704
|
-
/* Always reset function-based ADD_TAGS / ADD_ATTR checks to prevent
|
|
705
|
-
* leaking across calls when switching from function to array config */
|
|
706
|
-
EXTRA_ELEMENT_HANDLING.tagCheck = null;
|
|
707
|
-
EXTRA_ELEMENT_HANDLING.attributeCheck = null;
|
|
708
624
|
/* Merge configuration parameters */
|
|
709
|
-
if (
|
|
625
|
+
if (cfg.ADD_TAGS) {
|
|
710
626
|
if (typeof cfg.ADD_TAGS === 'function') {
|
|
711
627
|
EXTRA_ELEMENT_HANDLING.tagCheck = cfg.ADD_TAGS;
|
|
712
|
-
} else
|
|
628
|
+
} else {
|
|
713
629
|
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
|
|
714
630
|
ALLOWED_TAGS = clone(ALLOWED_TAGS);
|
|
715
631
|
}
|
|
716
632
|
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
|
|
717
633
|
}
|
|
718
634
|
}
|
|
719
|
-
if (
|
|
635
|
+
if (cfg.ADD_ATTR) {
|
|
720
636
|
if (typeof cfg.ADD_ATTR === 'function') {
|
|
721
637
|
EXTRA_ELEMENT_HANDLING.attributeCheck = cfg.ADD_ATTR;
|
|
722
|
-
} else
|
|
638
|
+
} else {
|
|
723
639
|
if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
|
|
724
640
|
ALLOWED_ATTR = clone(ALLOWED_ATTR);
|
|
725
641
|
}
|
|
726
642
|
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
|
|
727
643
|
}
|
|
728
644
|
}
|
|
729
|
-
if (
|
|
645
|
+
if (cfg.ADD_URI_SAFE_ATTR) {
|
|
730
646
|
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
|
|
731
647
|
}
|
|
732
|
-
if (
|
|
648
|
+
if (cfg.FORBID_CONTENTS) {
|
|
733
649
|
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
|
|
734
650
|
FORBID_CONTENTS = clone(FORBID_CONTENTS);
|
|
735
651
|
}
|
|
736
652
|
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
|
|
737
653
|
}
|
|
738
|
-
if (objectHasOwnProperty(cfg, 'ADD_FORBID_CONTENTS') && arrayIsArray(cfg.ADD_FORBID_CONTENTS)) {
|
|
739
|
-
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
|
|
740
|
-
FORBID_CONTENTS = clone(FORBID_CONTENTS);
|
|
741
|
-
}
|
|
742
|
-
addToSet(FORBID_CONTENTS, cfg.ADD_FORBID_CONTENTS, transformCaseFunc);
|
|
743
|
-
}
|
|
744
654
|
/* Add #text in case KEEP_CONTENT is set to true */
|
|
745
655
|
if (KEEP_CONTENT) {
|
|
746
656
|
ALLOWED_TAGS['#text'] = true;
|
|
@@ -1027,11 +937,6 @@ function createDOMPurify() {
|
|
|
1027
937
|
_forceRemove(currentNode);
|
|
1028
938
|
return true;
|
|
1029
939
|
}
|
|
1030
|
-
/* Remove risky CSS construction leading to mXSS */
|
|
1031
|
-
if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && tagName === 'style' && _isNode(currentNode.firstElementChild)) {
|
|
1032
|
-
_forceRemove(currentNode);
|
|
1033
|
-
return true;
|
|
1034
|
-
}
|
|
1035
940
|
/* Remove any occurrence of processing instructions */
|
|
1036
941
|
if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
|
|
1037
942
|
_forceRemove(currentNode);
|
|
@@ -1043,7 +948,7 @@ function createDOMPurify() {
|
|
|
1043
948
|
return true;
|
|
1044
949
|
}
|
|
1045
950
|
/* Remove element if anything forbids its presence */
|
|
1046
|
-
if (
|
|
951
|
+
if (!(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName])) {
|
|
1047
952
|
/* Check if we have a custom element to handle */
|
|
1048
953
|
if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
|
|
1049
954
|
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
|
|
@@ -1061,6 +966,7 @@ function createDOMPurify() {
|
|
|
1061
966
|
const childCount = childNodes.length;
|
|
1062
967
|
for (let i = childCount - 1; i >= 0; --i) {
|
|
1063
968
|
const childClone = cloneNode(childNodes[i], true);
|
|
969
|
+
childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
|
|
1064
970
|
parentNode.insertBefore(childClone, getNextSibling(currentNode));
|
|
1065
971
|
}
|
|
1066
972
|
}
|
|
@@ -1082,7 +988,7 @@ function createDOMPurify() {
|
|
|
1082
988
|
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
|
|
1083
989
|
/* Get the element's text content */
|
|
1084
990
|
content = currentNode.textContent;
|
|
1085
|
-
arrayForEach([MUSTACHE_EXPR
|
|
991
|
+
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
|
1086
992
|
content = stringReplace(content, expr, ' ');
|
|
1087
993
|
});
|
|
1088
994
|
if (currentNode.textContent !== content) {
|
|
@@ -1106,20 +1012,15 @@ function createDOMPurify() {
|
|
|
1106
1012
|
*/
|
|
1107
1013
|
// eslint-disable-next-line complexity
|
|
1108
1014
|
const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
|
|
1109
|
-
/* FORBID_ATTR must always win, even if ADD_ATTR predicate would allow it */
|
|
1110
|
-
if (FORBID_ATTR[lcName]) {
|
|
1111
|
-
return false;
|
|
1112
|
-
}
|
|
1113
1015
|
/* Make sure attribute cannot clobber */
|
|
1114
1016
|
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
|
|
1115
1017
|
return false;
|
|
1116
1018
|
}
|
|
1117
|
-
const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag);
|
|
1118
1019
|
/* Allow valid data-* attributes: At least one character after "-"
|
|
1119
1020
|
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
|
|
1120
1021
|
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
|
1121
1022
|
We don't need to check the value; it's always URI safe. */
|
|
1122
|
-
if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR
|
|
1023
|
+
if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
|
|
1123
1024
|
if (
|
|
1124
1025
|
// First condition does a very basic check if a) it's basically a valid custom element tagname AND
|
|
1125
1026
|
// b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
@@ -1131,15 +1032,11 @@ function createDOMPurify() {
|
|
|
1131
1032
|
return false;
|
|
1132
1033
|
}
|
|
1133
1034
|
/* Check value is safe. First, is attr inert? If so, is safe */
|
|
1134
|
-
} else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE
|
|
1035
|
+
} else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if (value) {
|
|
1135
1036
|
return false;
|
|
1136
1037
|
} else ;
|
|
1137
1038
|
return true;
|
|
1138
1039
|
};
|
|
1139
|
-
/* Names the HTML spec reserves from valid-custom-element-name; these must
|
|
1140
|
-
* never be treated as basic custom elements even when a permissive
|
|
1141
|
-
* CUSTOM_ELEMENT_HANDLING.tagNameCheck is configured. */
|
|
1142
|
-
const RESERVED_CUSTOM_ELEMENT_NAMES = addToSet({}, ['annotation-xml', 'color-profile', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'missing-glyph']);
|
|
1143
1040
|
/**
|
|
1144
1041
|
* _isBasicCustomElement
|
|
1145
1042
|
* checks if at least one dash is included in tagName, and it's not the first char
|
|
@@ -1149,7 +1046,7 @@ function createDOMPurify() {
|
|
|
1149
1046
|
* @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
|
|
1150
1047
|
*/
|
|
1151
1048
|
const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
|
|
1152
|
-
return
|
|
1049
|
+
return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);
|
|
1153
1050
|
};
|
|
1154
1051
|
/**
|
|
1155
1052
|
* _sanitizeAttributes
|
|
@@ -1164,7 +1061,9 @@ function createDOMPurify() {
|
|
|
1164
1061
|
const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
|
|
1165
1062
|
/* Execute a hook if present */
|
|
1166
1063
|
_executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
|
|
1167
|
-
const
|
|
1064
|
+
const {
|
|
1065
|
+
attributes
|
|
1066
|
+
} = currentNode;
|
|
1168
1067
|
/* Check if we have attributes; if not we might have a text node */
|
|
1169
1068
|
if (!attributes || _isClobbered(currentNode)) {
|
|
1170
1069
|
return;
|
|
@@ -1180,9 +1079,11 @@ function createDOMPurify() {
|
|
|
1180
1079
|
/* Go backwards over all attributes; safely remove bad ones */
|
|
1181
1080
|
while (l--) {
|
|
1182
1081
|
const attr = attributes[l];
|
|
1183
|
-
const
|
|
1184
|
-
|
|
1185
|
-
|
|
1082
|
+
const {
|
|
1083
|
+
name,
|
|
1084
|
+
namespaceURI,
|
|
1085
|
+
value: attrValue
|
|
1086
|
+
} = attr;
|
|
1186
1087
|
const lcName = transformCaseFunc(name);
|
|
1187
1088
|
const initValue = attrValue;
|
|
1188
1089
|
let value = name === 'value' ? initValue : stringTrim(initValue);
|
|
@@ -1196,16 +1097,14 @@ function createDOMPurify() {
|
|
|
1196
1097
|
/* Full DOM Clobbering protection via namespace isolation,
|
|
1197
1098
|
* Prefix id and name attributes with `user-content-`
|
|
1198
1099
|
*/
|
|
1199
|
-
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')
|
|
1100
|
+
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
|
|
1200
1101
|
// Remove the attribute with this value
|
|
1201
1102
|
_removeAttribute(name, currentNode);
|
|
1202
1103
|
// Prefix the value and later re-create the attribute with the sanitized value
|
|
1203
1104
|
value = SANITIZE_NAMED_PROPS_PREFIX + value;
|
|
1204
1105
|
}
|
|
1205
|
-
// Else: already prefixed, leave the attribute alone — the prefix is
|
|
1206
|
-
// itself the clobbering protection, and re-applying it is incorrect.
|
|
1207
1106
|
/* Work around a security issue with comments inside attributes */
|
|
1208
|
-
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|
|
|
1107
|
+
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title|textarea)/i, value)) {
|
|
1209
1108
|
_removeAttribute(name, currentNode);
|
|
1210
1109
|
continue;
|
|
1211
1110
|
}
|
|
@@ -1230,7 +1129,7 @@ function createDOMPurify() {
|
|
|
1230
1129
|
}
|
|
1231
1130
|
/* Sanitize attribute content to be template-safe */
|
|
1232
1131
|
if (SAFE_FOR_TEMPLATES) {
|
|
1233
|
-
arrayForEach([MUSTACHE_EXPR
|
|
1132
|
+
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
|
1234
1133
|
value = stringReplace(value, expr, ' ');
|
|
1235
1134
|
});
|
|
1236
1135
|
}
|
|
@@ -1284,7 +1183,7 @@ function createDOMPurify() {
|
|
|
1284
1183
|
*
|
|
1285
1184
|
* @param fragment to iterate over recursively
|
|
1286
1185
|
*/
|
|
1287
|
-
const
|
|
1186
|
+
const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
|
|
1288
1187
|
let shadowNode = null;
|
|
1289
1188
|
const shadowIterator = _createNodeIterator(fragment);
|
|
1290
1189
|
/* Execute a hook if present */
|
|
@@ -1298,55 +1197,12 @@ function createDOMPurify() {
|
|
|
1298
1197
|
_sanitizeAttributes(shadowNode);
|
|
1299
1198
|
/* Deep shadow DOM detected */
|
|
1300
1199
|
if (shadowNode.content instanceof DocumentFragment) {
|
|
1301
|
-
|
|
1200
|
+
_sanitizeShadowDOM(shadowNode.content);
|
|
1302
1201
|
}
|
|
1303
1202
|
}
|
|
1304
1203
|
/* Execute a hook if present */
|
|
1305
1204
|
_executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
|
|
1306
1205
|
};
|
|
1307
|
-
/**
|
|
1308
|
-
* _sanitizeAttachedShadowRoots
|
|
1309
|
-
*
|
|
1310
|
-
* Walks `root` and feeds every attached shadow root we encounter into
|
|
1311
|
-
* the existing _sanitizeShadowDOM pipeline. The default node iterator
|
|
1312
|
-
* does not descend into shadow trees, so nodes inside an attached
|
|
1313
|
-
* shadow root would otherwise be skipped entirely.
|
|
1314
|
-
*
|
|
1315
|
-
* Two real input paths put attached shadow roots in front of us:
|
|
1316
|
-
* 1. IN_PLACE on a DOM node that already has shadow roots attached.
|
|
1317
|
-
* 2. DOM-node input where importNode(dirty, true) deep-clones the
|
|
1318
|
-
* shadow root because it was created with `clonable: true`.
|
|
1319
|
-
*
|
|
1320
|
-
* This pass runs once, up front, so the main iteration loop (and the
|
|
1321
|
-
* existing _sanitizeShadowDOM template-content recursion) stay
|
|
1322
|
-
* untouched — string-input paths are not affected.
|
|
1323
|
-
*
|
|
1324
|
-
* @param root the subtree root to walk for attached shadow roots
|
|
1325
|
-
*/
|
|
1326
|
-
const _sanitizeAttachedShadowRoots2 = function _sanitizeAttachedShadowRoots(root) {
|
|
1327
|
-
if (root.nodeType === NODE_TYPE.element && root.shadowRoot instanceof DocumentFragment) {
|
|
1328
|
-
const sr = root.shadowRoot;
|
|
1329
|
-
// Recurse first so that nested shadow roots are reached even if
|
|
1330
|
-
// _sanitizeShadowDOM removes hosts at this level.
|
|
1331
|
-
_sanitizeAttachedShadowRoots2(sr);
|
|
1332
|
-
_sanitizeShadowDOM2(sr);
|
|
1333
|
-
}
|
|
1334
|
-
// Snapshot children before recursing. Sanitization of one subtree
|
|
1335
|
-
// (e.g. via an uponSanitizeShadowNode hook) may detach siblings,
|
|
1336
|
-
// and naive nextSibling traversal would silently skip the rest of
|
|
1337
|
-
// the list once a node is detached.
|
|
1338
|
-
const childNodes = root.childNodes;
|
|
1339
|
-
if (!childNodes) {
|
|
1340
|
-
return;
|
|
1341
|
-
}
|
|
1342
|
-
const snapshot = [];
|
|
1343
|
-
arrayForEach(childNodes, child => {
|
|
1344
|
-
arrayPush(snapshot, child);
|
|
1345
|
-
});
|
|
1346
|
-
for (const child of snapshot) {
|
|
1347
|
-
_sanitizeAttachedShadowRoots2(child);
|
|
1348
|
-
}
|
|
1349
|
-
};
|
|
1350
1206
|
// eslint-disable-next-line complexity
|
|
1351
1207
|
DOMPurify.sanitize = function (dirty) {
|
|
1352
1208
|
let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
@@ -1363,9 +1219,13 @@ function createDOMPurify() {
|
|
|
1363
1219
|
}
|
|
1364
1220
|
/* Stringify, in case dirty is an object */
|
|
1365
1221
|
if (typeof dirty !== 'string' && !_isNode(dirty)) {
|
|
1366
|
-
dirty
|
|
1367
|
-
|
|
1368
|
-
|
|
1222
|
+
if (typeof dirty.toString === 'function') {
|
|
1223
|
+
dirty = dirty.toString();
|
|
1224
|
+
if (typeof dirty !== 'string') {
|
|
1225
|
+
throw typeErrorCreate('dirty is not a string, aborting');
|
|
1226
|
+
}
|
|
1227
|
+
} else {
|
|
1228
|
+
throw typeErrorCreate('toString is not a function');
|
|
1369
1229
|
}
|
|
1370
1230
|
}
|
|
1371
1231
|
/* Return dirty HTML if DOMPurify cannot run */
|
|
@@ -1384,16 +1244,12 @@ function createDOMPurify() {
|
|
|
1384
1244
|
}
|
|
1385
1245
|
if (IN_PLACE) {
|
|
1386
1246
|
/* Do some early pre-sanitization to avoid unsafe root nodes */
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
const tagName = transformCaseFunc(nn);
|
|
1247
|
+
if (dirty.nodeName) {
|
|
1248
|
+
const tagName = transformCaseFunc(dirty.nodeName);
|
|
1390
1249
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
1391
1250
|
throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
|
|
1392
1251
|
}
|
|
1393
1252
|
}
|
|
1394
|
-
/* Sanitize attached shadow roots before the main iterator runs.
|
|
1395
|
-
The iterator does not descend into shadow trees. */
|
|
1396
|
-
_sanitizeAttachedShadowRoots2(dirty);
|
|
1397
1253
|
} else if (dirty instanceof Node) {
|
|
1398
1254
|
/* If dirty is a DOM element, append to an empty document to avoid
|
|
1399
1255
|
elements being stripped by the parser */
|
|
@@ -1408,10 +1264,6 @@ function createDOMPurify() {
|
|
|
1408
1264
|
// eslint-disable-next-line unicorn/prefer-dom-node-append
|
|
1409
1265
|
body.appendChild(importedNode);
|
|
1410
1266
|
}
|
|
1411
|
-
/* Clonable shadow roots are deep-cloned by importNode(); sanitize
|
|
1412
|
-
them before the main iterator runs, since the iterator does not
|
|
1413
|
-
descend into shadow trees. */
|
|
1414
|
-
_sanitizeAttachedShadowRoots2(importedNode);
|
|
1415
1267
|
} else {
|
|
1416
1268
|
/* Exit directly if we have nothing to do */
|
|
1417
1269
|
if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
|
|
@@ -1440,7 +1292,7 @@ function createDOMPurify() {
|
|
|
1440
1292
|
_sanitizeAttributes(currentNode);
|
|
1441
1293
|
/* Shadow DOM detected, sanitize it */
|
|
1442
1294
|
if (currentNode.content instanceof DocumentFragment) {
|
|
1443
|
-
|
|
1295
|
+
_sanitizeShadowDOM(currentNode.content);
|
|
1444
1296
|
}
|
|
1445
1297
|
}
|
|
1446
1298
|
/* If we sanitized `dirty` in-place, return it. */
|
|
@@ -1449,14 +1301,6 @@ function createDOMPurify() {
|
|
|
1449
1301
|
}
|
|
1450
1302
|
/* Return sanitized string or DOM */
|
|
1451
1303
|
if (RETURN_DOM) {
|
|
1452
|
-
if (SAFE_FOR_TEMPLATES) {
|
|
1453
|
-
body.normalize();
|
|
1454
|
-
let html = body.innerHTML;
|
|
1455
|
-
arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], expr => {
|
|
1456
|
-
html = stringReplace(html, expr, ' ');
|
|
1457
|
-
});
|
|
1458
|
-
body.innerHTML = html;
|
|
1459
|
-
}
|
|
1460
1304
|
if (RETURN_DOM_FRAGMENT) {
|
|
1461
1305
|
returnNode = createDocumentFragment.call(body.ownerDocument);
|
|
1462
1306
|
while (body.firstChild) {
|
|
@@ -1485,7 +1329,7 @@ function createDOMPurify() {
|
|
|
1485
1329
|
}
|
|
1486
1330
|
/* Sanitize final string template-safe */
|
|
1487
1331
|
if (SAFE_FOR_TEMPLATES) {
|
|
1488
|
-
arrayForEach([MUSTACHE_EXPR
|
|
1332
|
+
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
|
1489
1333
|
serializedHTML = stringReplace(serializedHTML, expr, ' ');
|
|
1490
1334
|
});
|
|
1491
1335
|
}
|