From 529f0ff8e6987b6a59006f866bb9b5851ee83976 Mon Sep 17 00:00:00 2001 From: aleksandr-js-developer Date: Sat, 24 Feb 2024 21:24:18 +0200 Subject: [PATCH] Vite: target to 'es6' --- dist/index.es.js | 73 ++++++++++++++++++++++--------------------- dist/index.es.js.map | 2 +- dist/index.umd.js | 4 +-- dist/index.umd.js.map | 2 +- package-lock.json | 4 +-- package.json | 2 +- vite.config.js | 2 +- 7 files changed, 46 insertions(+), 43 deletions(-) diff --git a/dist/index.es.js b/dist/index.es.js index 1d997fa..95396de 100644 --- a/dist/index.es.js +++ b/dist/index.es.js @@ -1,4 +1,7 @@ -const y = () => { +var w = Object.defineProperty; +var g = (e, t, r) => t in e ? w(e, t, { enumerable: !0, configurable: !0, writable: !0, value: r }) : e[t] = r; +var h = (e, t, r) => (g(e, typeof t != "symbol" ? t + "" : t, r), r); +const O = () => { if (globalThis.DOMParser === void 0) throw `globalThis.DOMParser is not defined! It seems that you use purify-html in node environment. @@ -13,13 +16,13 @@ See https://github.com/oleksandr-dukhovnyy/purify-html?tab=readme-ov-file#node-j return t.innerHTML; } }; -}, w = (e, t) => e.setAttribute(t, ""), h = (e) => { +}, j = (e, t) => e.setAttribute(t, ""), d = (e) => { if ("childNodes" in e) for (let t = e.childNodes.length - 1; t > 0; t--) e.childNodes[t].nodeType === 8 && e.childNodes[t].remove(); else return !1; -}, g = /* @__PURE__ */ (() => { +}, L = /* @__PURE__ */ (() => { const e = (t, r = 0) => { if (t._d = r, t.children.length) [...t.children].forEach((a) => e(a, r + 1)); @@ -27,7 +30,7 @@ See https://github.com/oleksandr-dukhovnyy/purify-html?tab=readme-ov-file#node-j return r; }; return (t) => (e(t), [...t.querySelectorAll("*")].sort((r, a) => a._d - r._d).map((r) => (delete r._d, r))); -})(), O = (e) => { +})(), k = (e) => { const t = []; return Object.prototype.hasOwnProperty.call(e, "attributes") || (e.attributes = []), e.attributes.forEach((r) => { switch (typeof r) { @@ -42,22 +45,22 @@ See https://github.com/oleksandr-dukhovnyy/purify-html?tab=readme-ov-file#node-j }, u = (e) => { try { return new URL(e); - } catch { + } catch (t) { return null; } -}, d = (e) => { +}, m = (e) => { if (typeof e == "string") return e; if (Array.isArray(e)) - return e.map((t) => d(t)); + return e.map((t) => m(t)); if (typeof e == "object" && e !== null) { const t = {}; for (const r in e) - e[r] instanceof RegExp ? t[r] = e[r] : typeof e[r] == "object" ? t[r] = d(e[r]) : t[r] = e[r]; + e[r] instanceof RegExp ? t[r] = e[r] : typeof e[r] == "object" ? t[r] = m(e[r]) : t[r] = e[r]; return t; } return e; -}, j = (e) => e.map(d), b = { +}, T = (e) => e.map(m), y = { /** * Check is str a correct link */ @@ -144,18 +147,18 @@ See https://github.com/oleksandr-dukhovnyy/purify-html?tab=readme-ov-file#node-j } }; let p; -class L { - /** - * Create PurifyHTML instance - */ - /** - * Is need to remove comments in root and in all nodes by default - */ - removeComments = !0; - allowedTags = {}; - whiteList; +class D { constructor(t = []) { - p || (p = y()), this.allowedTags = j(t).reduce( + /** + * Create PurifyHTML instance + */ + /** + * Is need to remove comments in root and in all nodes by default + */ + h(this, "removeComments", !0); + h(this, "allowedTags", {}); + h(this, "whiteList"); + p || (p = O()), this.allowedTags = T(t).reduce( (r, a) => { switch (typeof a) { case "string": { @@ -165,7 +168,7 @@ class L { case "object": r[a.name] = Object.assign( r[a.name] || {}, - O(a) + k(a) ); } return r; @@ -180,28 +183,28 @@ class L { */ sanitize(t) { const r = p.parse(t); - return this.removeComments && h(r), g(r).forEach((l) => { - const m = l.tagName.toLowerCase(); - if (this.whiteList.includes(m)) { - const f = this.allowedTags[m]; - if (this.removeComments && f.dontRemoveComments !== !0 && h(l), Object.prototype.hasOwnProperty.call(f, "attributes") && f.attributes.length > 0) { + return this.removeComments && d(r), L(r).forEach((l) => { + const v = l.tagName.toLowerCase(); + if (this.whiteList.includes(v)) { + const f = this.allowedTags[v]; + if (this.removeComments && f.dontRemoveComments !== !0 && d(l), Object.prototype.hasOwnProperty.call(f, "attributes") && f.attributes.length > 0) { const c = [], s = []; for (let i = 0; i < l.attributes.length; i++) { const n = l.attributes[i], o = f.attributes.find( - (v) => v.name === n.name + (b) => b.name === n.name ); o ? Object.prototype.hasOwnProperty.call(o, "value") && (typeof o.value == "string" ? n.value !== o.value && s.push(n.name) : typeof o.value == "function" ? o.value(n.value) || s.push(n.name) : o.value instanceof RegExp ? o.value.test(n.value) || s.push(n.name) : Array.isArray(o.value) ? o.value.includes(n.value) || s.push(n.name) : typeof o.value == "object" && Object.prototype.hasOwnProperty.call( o.value, "preset" ) && Object.prototype.hasOwnProperty.call( - b, + y, o.value.preset - ) ? b[o.value.preset](n.value).remove && s.push(n.name) : s.push(n.name)) : c.push(n.name); + ) ? y[o.value.preset](n.value).remove && s.push(n.name) : s.push(n.name)) : c.push(n.name); } c.forEach( (i) => l.removeAttribute(i) ), s.forEach( - (i) => w(l, i) + (i) => j(l, i) ); } else { const c = []; @@ -212,7 +215,7 @@ class L { ); } } else - this.removeComments && h(l), l.insertAdjacentHTML("afterend", l.innerHTML), l.remove(); + this.removeComments && d(l), l.insertAdjacentHTML("afterend", l.innerHTML), l.remove(); }), p.stringify(r); } /** @@ -222,7 +225,7 @@ class L { return t.split("").map((r) => `&#${r.charCodeAt(0)};`).join(""); } } -const k = (e) => e ? Object.prototype.hasOwnProperty.call(e, "parse") ? Object.prototype.hasOwnProperty.call(e, "stringify") ? (p = e, 1) : (console.error( +const A = (e) => e ? Object.prototype.hasOwnProperty.call(e, "parse") ? Object.prototype.hasOwnProperty.call(e, "stringify") ? (p = e, 1) : (console.error( 'cannot to find method "stringify" in custom parser!', e ), 0) : (console.error( @@ -230,8 +233,8 @@ const k = (e) => e ? Object.prototype.hasOwnProperty.call(e, "parse") ? Object.p e ), 0) : (console.error("customParser is null!"), 0); export { - L as default, - L as sanitizer, - k as setParser + D as default, + D as sanitizer, + A as setParser }; //# sourceMappingURL=index.es.js.map diff --git a/dist/index.es.js.map b/dist/index.es.js.map index 6d8cb6a..a464465 100644 --- a/dist/index.es.js.map +++ b/dist/index.es.js.map @@ -1 +1 @@ -{"version":3,"file":"index.es.js","sources":["../src/utils.ts","../src/core.ts"],"sourcesContent":["/** @module utils */\r\nimport {\r\n AttributeRule,\r\n TagRule,\r\n presetTestResult,\r\n MarkedElement,\r\n HTMLParser,\r\n} from './types';\r\n\r\n/**\r\n * Setup default parser\r\n */\r\nexport const getDefaultParser = (): HTMLParser => {\r\n if (globalThis.DOMParser === undefined) {\r\n throw 'globalThis.DOMParser is not defined!\\nIt seems that you use purify-html in node environment.\\nFor node environment you need to add HTML parser by yourself.\\nSee https://github.com/oleksandr-dukhovnyy/purify-html?tab=readme-ov-file#node-js for details.';\r\n }\r\n\r\n const elem: Element = new DOMParser()\r\n .parseFromString('', 'text/html')\r\n .querySelector('body');\r\n\r\n return {\r\n parse(string: string): Element {\r\n elem.innerHTML = string;\r\n return elem;\r\n },\r\n stringify(elem: Element): string {\r\n return elem.innerHTML;\r\n },\r\n };\r\n};\r\n\r\n/**\r\n * Remove attribute value, but dont remove attribute.\r\n */\r\nexport const removeAttributeValue = (node: Element, attributeName: string) =>\r\n node.setAttribute(attributeName, '');\r\n\r\n/**\r\n * Remove all comments in childNodes.\r\n * Comments in child nodes are not removed\r\n *\r\n * @param {HTMLElement} node\r\n * @returns {undefined | false} undefined - ok, false - error\r\n */\r\nexport const removeComments = (node: Element): undefined | false => {\r\n if ('childNodes' in node) {\r\n for (\r\n let childIndex = node.childNodes.length - 1;\r\n childIndex > 0;\r\n childIndex--\r\n ) {\r\n if (node.childNodes[childIndex].nodeType === 8) {\r\n node.childNodes[childIndex].remove();\r\n }\r\n }\r\n } else {\r\n return false;\r\n }\r\n};\r\n\r\n/**\r\n * @param {Element} node\r\n * @returns {Element[]} array of node childs sorted by child's max deep\r\n */\r\nexport const getSortedByMaxChildDeep = (() => {\r\n const markDeep = (node: MarkedElement, d = 0): number | undefined => {\r\n node._d = d;\r\n\r\n if (node.children.length) {\r\n [...node.children].forEach(n => markDeep(n, d + 1));\r\n } else {\r\n return d;\r\n }\r\n };\r\n\r\n return (node: Element): Element[] => {\r\n markDeep(node);\r\n\r\n return [...node.querySelectorAll('*')]\r\n .sort((a: MarkedElement, b: MarkedElement) => b._d - a._d)\r\n .map((el: MarkedElement): Element => {\r\n delete el._d;\r\n\r\n return el;\r\n });\r\n };\r\n})();\r\n\r\n/**\r\n * Normalize a TagRule.\r\n */\r\nexport const transformAttributes = (rule: TagRule): TagRule => {\r\n const res: AttributeRule[] = [];\r\n\r\n if (!Object.prototype.hasOwnProperty.call(rule, 'attributes')) {\r\n rule.attributes = [];\r\n }\r\n\r\n rule.attributes.forEach(attr => {\r\n switch (typeof attr) {\r\n case 'string':\r\n res.push({ name: attr });\r\n break;\r\n\r\n case 'object':\r\n res.push(attr);\r\n break;\r\n }\r\n });\r\n\r\n rule.attributes = res;\r\n\r\n return rule;\r\n};\r\n\r\n/**\r\n * Safely get link with try...catch.\r\n */\r\nexport const safelyGetLink = (str: string): URL | null => {\r\n try {\r\n return new URL(str);\r\n } catch (e) {\r\n return null;\r\n }\r\n};\r\n\r\n/**\r\n * Add prefix by check\r\n *\r\n * @returns {string} if check returns true - prefix + str, else str\r\n */\r\nexport const addPrefix = (str: string, check: RegExp, prefix: string) =>\r\n check.test(str) ? str : prefix + str;\r\n\r\n/**\r\n * Deep clone an object\r\n */\r\nexport const deepClone = (item: T): T => {\r\n if (typeof item === 'string') return item;\r\n if (Array.isArray(item))\r\n return item.map(arrItem => deepClone(arrItem)) as unknown as T;\r\n\r\n if (typeof item === 'object' && item !== null) {\r\n const res: Record = {};\r\n\r\n for (const key in item) {\r\n if (item[key] instanceof RegExp) {\r\n res[key] = item[key];\r\n } else if (typeof item[key] === 'object') {\r\n res[key] = deepClone(item[key]);\r\n } else {\r\n res[key] = item[key];\r\n }\r\n }\r\n\r\n return res as T;\r\n }\r\n\r\n return item;\r\n};\r\n\r\n/**\r\n * Create clone of config for safe mutations\r\n *\r\n * @param {string[] | TagRule[]} config\r\n * @returns {string[] | TagRule[]} cloned config\r\n */\r\nexport const copyConfig = (\r\n config: (string | TagRule)[]\r\n): (string | TagRule)[] => config.map(deepClone);\r\n\r\n/**\r\n * @typedef PresetCheckResult\r\n * @type {object}\r\n * @property {boolean} remove if true - attribute value is incorrect\r\n */\r\n\r\n/**\r\n * Interface for presets.\r\n *\r\n * @interface\r\n */\r\nexport const valuesPresets = {\r\n /**\r\n * Check is str a correct link\r\n */\r\n '%correct-link%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n return {\r\n remove: safelyGetLink(str) === null,\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has HTTP protocol\r\n */\r\n '%http-link%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.protocol !== 'http:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has HTTPS protocol\r\n */\r\n '%https-link%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.protocol !== 'https:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has FTP protocol\r\n */\r\n '%ftp-link%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.protocol !== 'ftp:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has HTTPS protocol and does not have a params\r\n *\r\n * @function\r\n */\r\n '%https-link-without-search-params%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.search !== '' || url.protocol !== 'https:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has HTTP protocol and does not have a params\r\n */\r\n '%http-link-without-search-params%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.search !== '' || url.protocol !== 'http:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has same origin with current `location.origin`\r\n */\r\n '%same-origin%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || globalThis.location.origin !== url.origin,\r\n };\r\n },\r\n};\r\n","/** @module core */\r\nimport { TagRule, AttributeRule, HTMLParser } from './types';\r\n\r\nimport {\r\n removeAttributeValue,\r\n transformAttributes,\r\n valuesPresets,\r\n getSortedByMaxChildDeep,\r\n copyConfig,\r\n removeComments,\r\n getDefaultParser,\r\n} from './utils';\r\n\r\nlet parser: HTMLParser | undefined;\r\n\r\n/**\r\n * Purify instance.\r\n */\r\nexport class PurifyHTML {\r\n /**\r\n * Create PurifyHTML instance\r\n */\r\n\r\n /**\r\n * Is need to remove comments in root and in all nodes by default\r\n */\r\n protected removeComments = true;\r\n protected allowedTags: { [key: string]: TagRule } = {};\r\n protected whiteList: string[];\r\n\r\n constructor(allowedTags: TagRule[] | string[] = []) {\r\n // setup default parser\r\n if (!parser) {\r\n parser = getDefaultParser();\r\n }\r\n\r\n /**\r\n * Copy and compile a rules\r\n */\r\n this.allowedTags = copyConfig(allowedTags).reduce(\r\n (acc: object, curr: TagRule | string) => {\r\n switch (typeof curr) {\r\n case 'string': {\r\n if (curr === '#comments') {\r\n this.removeComments = false;\r\n } else {\r\n acc[curr] = Object.assign(acc[curr] || {}, {});\r\n }\r\n\r\n break;\r\n }\r\n case 'object':\r\n acc[curr.name] = Object.assign(\r\n acc[curr.name] || {},\r\n transformAttributes(curr)\r\n );\r\n }\r\n\r\n return acc;\r\n },\r\n {}\r\n );\r\n\r\n /**\r\n * Copy and compile a rules\r\n */\r\n this.whiteList = Object.keys(this.allowedTags);\r\n\r\n /**\r\n * Bind context for method sanitize\r\n */\r\n this.sanitize.bind(this);\r\n }\r\n\r\n /**\r\n * Sanitize a string.\r\n * @param {string} str to needs to sanitize.\r\n * @return {string} A string cleared according to the rules from this.allowedTags.\r\n */\r\n public sanitize(str: string): string {\r\n const wrapper: Element = parser.parse(str);\r\n\r\n if (this.removeComments) {\r\n removeComments(wrapper);\r\n }\r\n\r\n const allItems: Element[] = getSortedByMaxChildDeep(wrapper);\r\n\r\n allItems.forEach((tag: Element) => {\r\n const name = tag.tagName.toLowerCase();\r\n\r\n if (this.whiteList.includes(name)) {\r\n const tagConfig: TagRule = this.allowedTags[name];\r\n\r\n if (this.removeComments && tagConfig.dontRemoveComments !== true) {\r\n removeComments(tag);\r\n }\r\n\r\n if (\r\n Object.prototype.hasOwnProperty.call(tagConfig, 'attributes') &&\r\n tagConfig.attributes.length > 0\r\n ) {\r\n const deleteList: string[] = [];\r\n const clearList: string[] = [];\r\n\r\n for (let i = 0; i < tag.attributes.length; i++) {\r\n const attr: Attr = tag.attributes[i];\r\n\r\n // get attribute rules\r\n const attributeRules = tagConfig.attributes.find(\r\n (attrRule: AttributeRule) => attrRule.name === attr.name\r\n );\r\n\r\n if (!attributeRules) {\r\n // if rules not defined\r\n deleteList.push(attr.name);\r\n } else if (\r\n Object.prototype.hasOwnProperty.call(attributeRules, 'value')\r\n ) {\r\n // if rules defined\r\n if (typeof attributeRules.value === 'string') {\r\n if (attr.value !== attributeRules.value) {\r\n // if rules is string\r\n clearList.push(attr.name);\r\n }\r\n } else if (typeof attributeRules.value === 'function') {\r\n if (!attributeRules.value(attr.value)) {\r\n clearList.push(attr.name);\r\n }\r\n } else if (attributeRules.value instanceof RegExp) {\r\n // if rules is regexp\r\n if (!attributeRules.value.test(attr.value)) {\r\n clearList.push(attr.name);\r\n }\r\n } else if (Array.isArray(attributeRules.value)) {\r\n // if rules is an array (an array of strings - valid values)\r\n if (!attributeRules.value.includes(attr.value)) {\r\n clearList.push(attr.name);\r\n }\r\n } else if (typeof attributeRules.value === 'object') {\r\n if (\r\n Object.prototype.hasOwnProperty.call(\r\n attributeRules.value,\r\n 'preset'\r\n )\r\n ) {\r\n // if rules is preset\r\n\r\n if (\r\n Object.prototype.hasOwnProperty.call(\r\n valuesPresets,\r\n attributeRules.value.preset\r\n )\r\n ) {\r\n const presetRes = valuesPresets[\r\n attributeRules.value.preset\r\n ](attr.value);\r\n\r\n if (presetRes.remove) {\r\n clearList.push(attr.name);\r\n }\r\n } else {\r\n clearList.push(attr.name);\r\n }\r\n } else {\r\n // remove attribute if get empty object\r\n clearList.push(attr.name);\r\n }\r\n } else {\r\n // remove attribute value by default\r\n clearList.push(attr.name);\r\n }\r\n }\r\n }\r\n\r\n deleteList.forEach((attrName: string) =>\r\n tag.removeAttribute(attrName)\r\n );\r\n clearList.forEach((attrName: string) =>\r\n removeAttributeValue(tag, attrName)\r\n );\r\n } else {\r\n const deleteList: string[] = [];\r\n\r\n for (let i = 0; i < tag.attributes.length; i++) {\r\n deleteList.push(tag.attributes[i].name);\r\n }\r\n\r\n deleteList.forEach((attrName: string) =>\r\n tag.removeAttribute(attrName)\r\n );\r\n }\r\n } else {\r\n if (this.removeComments) {\r\n removeComments(tag);\r\n }\r\n\r\n tag.insertAdjacentHTML('afterend', tag.innerHTML);\r\n tag.remove();\r\n }\r\n });\r\n\r\n return parser.stringify(wrapper);\r\n }\r\n\r\n /**\r\n * Convert a string to {@link https://www.w3schools.com/html/html_entities.asp HTML Entities}.\r\n */\r\n public toHTMLEntities(str: string): string {\r\n return str\r\n .split('')\r\n .map(n => `&#${n.charCodeAt(0)};`)\r\n .join('');\r\n }\r\n}\r\n\r\n/**\r\n * Set HTML custom parser\r\n */\r\nexport const setParser = (\r\n customParser: HTMLParser | null | undefined\r\n): number => {\r\n if (!customParser) {\r\n console.error('customParser is null!');\r\n return 0;\r\n }\r\n\r\n if (!Object.prototype.hasOwnProperty.call(customParser, 'parse')) {\r\n console.error(\r\n 'cannot to find method \"parse\" in custom parser!',\r\n customParser\r\n );\r\n\r\n return 0;\r\n }\r\n\r\n if (!Object.prototype.hasOwnProperty.call(customParser, 'stringify')) {\r\n console.error(\r\n 'cannot to find method \"stringify\" in custom parser!',\r\n customParser\r\n );\r\n\r\n return 0;\r\n }\r\n\r\n parser = customParser;\r\n return 1;\r\n};\r\n\r\nexport default PurifyHTML;\r\n"],"names":["getDefaultParser","elem","string","removeAttributeValue","node","attributeName","removeComments","childIndex","getSortedByMaxChildDeep","markDeep","d","n","a","b","el","transformAttributes","rule","res","attr","safelyGetLink","str","deepClone","item","arrItem","key","copyConfig","config","valuesPresets","url","parser","PurifyHTML","allowedTags","acc","curr","wrapper","tag","name","tagConfig","deleteList","clearList","attributeRules","attrRule","attrName","i","setParser","customParser"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.es.js","sources":["../src/utils.ts","../src/core.ts"],"sourcesContent":["/** @module utils */\r\nimport {\r\n AttributeRule,\r\n TagRule,\r\n presetTestResult,\r\n MarkedElement,\r\n HTMLParser,\r\n} from './types';\r\n\r\n/**\r\n * Setup default parser\r\n */\r\nexport const getDefaultParser = (): HTMLParser => {\r\n if (globalThis.DOMParser === undefined) {\r\n throw 'globalThis.DOMParser is not defined!\\nIt seems that you use purify-html in node environment.\\nFor node environment you need to add HTML parser by yourself.\\nSee https://github.com/oleksandr-dukhovnyy/purify-html?tab=readme-ov-file#node-js for details.';\r\n }\r\n\r\n const elem: Element = new DOMParser()\r\n .parseFromString('', 'text/html')\r\n .querySelector('body');\r\n\r\n return {\r\n parse(string: string): Element {\r\n elem.innerHTML = string;\r\n return elem;\r\n },\r\n stringify(elem: Element): string {\r\n return elem.innerHTML;\r\n },\r\n };\r\n};\r\n\r\n/**\r\n * Remove attribute value, but dont remove attribute.\r\n */\r\nexport const removeAttributeValue = (node: Element, attributeName: string) =>\r\n node.setAttribute(attributeName, '');\r\n\r\n/**\r\n * Remove all comments in childNodes.\r\n * Comments in child nodes are not removed\r\n *\r\n * @param {HTMLElement} node\r\n * @returns {undefined | false} undefined - ok, false - error\r\n */\r\nexport const removeComments = (node: Element): undefined | false => {\r\n if ('childNodes' in node) {\r\n for (\r\n let childIndex = node.childNodes.length - 1;\r\n childIndex > 0;\r\n childIndex--\r\n ) {\r\n if (node.childNodes[childIndex].nodeType === 8) {\r\n node.childNodes[childIndex].remove();\r\n }\r\n }\r\n } else {\r\n return false;\r\n }\r\n};\r\n\r\n/**\r\n * @param {Element} node\r\n * @returns {Element[]} array of node childs sorted by child's max deep\r\n */\r\nexport const getSortedByMaxChildDeep = (() => {\r\n const markDeep = (node: MarkedElement, d = 0): number | undefined => {\r\n node._d = d;\r\n\r\n if (node.children.length) {\r\n [...node.children].forEach(n => markDeep(n, d + 1));\r\n } else {\r\n return d;\r\n }\r\n };\r\n\r\n return (node: Element): Element[] => {\r\n markDeep(node);\r\n\r\n return [...node.querySelectorAll('*')]\r\n .sort((a: MarkedElement, b: MarkedElement) => b._d - a._d)\r\n .map((el: MarkedElement): Element => {\r\n delete el._d;\r\n\r\n return el;\r\n });\r\n };\r\n})();\r\n\r\n/**\r\n * Normalize a TagRule.\r\n */\r\nexport const transformAttributes = (rule: TagRule): TagRule => {\r\n const res: AttributeRule[] = [];\r\n\r\n if (!Object.prototype.hasOwnProperty.call(rule, 'attributes')) {\r\n rule.attributes = [];\r\n }\r\n\r\n rule.attributes.forEach(attr => {\r\n switch (typeof attr) {\r\n case 'string':\r\n res.push({ name: attr });\r\n break;\r\n\r\n case 'object':\r\n res.push(attr);\r\n break;\r\n }\r\n });\r\n\r\n rule.attributes = res;\r\n\r\n return rule;\r\n};\r\n\r\n/**\r\n * Safely get link with try...catch.\r\n */\r\nexport const safelyGetLink = (str: string): URL | null => {\r\n try {\r\n return new URL(str);\r\n } catch (e) {\r\n return null;\r\n }\r\n};\r\n\r\n/**\r\n * Add prefix by check\r\n *\r\n * @returns {string} if check returns true - prefix + str, else str\r\n */\r\nexport const addPrefix = (str: string, check: RegExp, prefix: string) =>\r\n check.test(str) ? str : prefix + str;\r\n\r\n/**\r\n * Deep clone an object\r\n */\r\nexport const deepClone = (item: T): T => {\r\n if (typeof item === 'string') return item;\r\n if (Array.isArray(item))\r\n return item.map(arrItem => deepClone(arrItem)) as unknown as T;\r\n\r\n if (typeof item === 'object' && item !== null) {\r\n const res: Record = {};\r\n\r\n for (const key in item) {\r\n if (item[key] instanceof RegExp) {\r\n res[key] = item[key];\r\n } else if (typeof item[key] === 'object') {\r\n res[key] = deepClone(item[key]);\r\n } else {\r\n res[key] = item[key];\r\n }\r\n }\r\n\r\n return res as T;\r\n }\r\n\r\n return item;\r\n};\r\n\r\n/**\r\n * Create clone of config for safe mutations\r\n *\r\n * @param {string[] | TagRule[]} config\r\n * @returns {string[] | TagRule[]} cloned config\r\n */\r\nexport const copyConfig = (\r\n config: (string | TagRule)[]\r\n): (string | TagRule)[] => config.map(deepClone);\r\n\r\n/**\r\n * @typedef PresetCheckResult\r\n * @type {object}\r\n * @property {boolean} remove if true - attribute value is incorrect\r\n */\r\n\r\n/**\r\n * Interface for presets.\r\n *\r\n * @interface\r\n */\r\nexport const valuesPresets = {\r\n /**\r\n * Check is str a correct link\r\n */\r\n '%correct-link%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n return {\r\n remove: safelyGetLink(str) === null,\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has HTTP protocol\r\n */\r\n '%http-link%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.protocol !== 'http:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has HTTPS protocol\r\n */\r\n '%https-link%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.protocol !== 'https:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has FTP protocol\r\n */\r\n '%ftp-link%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.protocol !== 'ftp:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has HTTPS protocol and does not have a params\r\n *\r\n * @function\r\n */\r\n '%https-link-without-search-params%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.search !== '' || url.protocol !== 'https:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has HTTP protocol and does not have a params\r\n */\r\n '%http-link-without-search-params%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.search !== '' || url.protocol !== 'http:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has same origin with current `location.origin`\r\n */\r\n '%same-origin%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || globalThis.location.origin !== url.origin,\r\n };\r\n },\r\n};\r\n","/** @module core */\r\nimport { TagRule, AttributeRule, HTMLParser } from './types';\r\n\r\nimport {\r\n removeAttributeValue,\r\n transformAttributes,\r\n valuesPresets,\r\n getSortedByMaxChildDeep,\r\n copyConfig,\r\n removeComments,\r\n getDefaultParser,\r\n} from './utils';\r\n\r\nlet parser: HTMLParser | undefined;\r\n\r\n/**\r\n * Purify instance.\r\n */\r\nexport class PurifyHTML {\r\n /**\r\n * Create PurifyHTML instance\r\n */\r\n\r\n /**\r\n * Is need to remove comments in root and in all nodes by default\r\n */\r\n protected removeComments = true;\r\n protected allowedTags: { [key: string]: TagRule } = {};\r\n protected whiteList: string[];\r\n\r\n constructor(allowedTags: TagRule[] | string[] = []) {\r\n // setup default parser\r\n if (!parser) {\r\n parser = getDefaultParser();\r\n }\r\n\r\n /**\r\n * Copy and compile a rules\r\n */\r\n this.allowedTags = copyConfig(allowedTags).reduce(\r\n (acc: object, curr: TagRule | string) => {\r\n switch (typeof curr) {\r\n case 'string': {\r\n if (curr === '#comments') {\r\n this.removeComments = false;\r\n } else {\r\n acc[curr] = Object.assign(acc[curr] || {}, {});\r\n }\r\n\r\n break;\r\n }\r\n case 'object':\r\n acc[curr.name] = Object.assign(\r\n acc[curr.name] || {},\r\n transformAttributes(curr)\r\n );\r\n }\r\n\r\n return acc;\r\n },\r\n {}\r\n );\r\n\r\n /**\r\n * Copy and compile a rules\r\n */\r\n this.whiteList = Object.keys(this.allowedTags);\r\n\r\n /**\r\n * Bind context for method sanitize\r\n */\r\n this.sanitize.bind(this);\r\n }\r\n\r\n /**\r\n * Sanitize a string.\r\n * @param {string} str to needs to sanitize.\r\n * @return {string} A string cleared according to the rules from this.allowedTags.\r\n */\r\n public sanitize(str: string): string {\r\n const wrapper: Element = parser.parse(str);\r\n\r\n if (this.removeComments) {\r\n removeComments(wrapper);\r\n }\r\n\r\n const allItems: Element[] = getSortedByMaxChildDeep(wrapper);\r\n\r\n allItems.forEach((tag: Element) => {\r\n const name = tag.tagName.toLowerCase();\r\n\r\n if (this.whiteList.includes(name)) {\r\n const tagConfig: TagRule = this.allowedTags[name];\r\n\r\n if (this.removeComments && tagConfig.dontRemoveComments !== true) {\r\n removeComments(tag);\r\n }\r\n\r\n if (\r\n Object.prototype.hasOwnProperty.call(tagConfig, 'attributes') &&\r\n tagConfig.attributes.length > 0\r\n ) {\r\n const deleteList: string[] = [];\r\n const clearList: string[] = [];\r\n\r\n for (let i = 0; i < tag.attributes.length; i++) {\r\n const attr: Attr = tag.attributes[i];\r\n\r\n // get attribute rules\r\n const attributeRules = tagConfig.attributes.find(\r\n (attrRule: AttributeRule) => attrRule.name === attr.name\r\n );\r\n\r\n if (!attributeRules) {\r\n // if rules not defined\r\n deleteList.push(attr.name);\r\n } else if (\r\n Object.prototype.hasOwnProperty.call(attributeRules, 'value')\r\n ) {\r\n // if rules defined\r\n if (typeof attributeRules.value === 'string') {\r\n if (attr.value !== attributeRules.value) {\r\n // if rules is string\r\n clearList.push(attr.name);\r\n }\r\n } else if (typeof attributeRules.value === 'function') {\r\n if (!attributeRules.value(attr.value)) {\r\n clearList.push(attr.name);\r\n }\r\n } else if (attributeRules.value instanceof RegExp) {\r\n // if rules is regexp\r\n if (!attributeRules.value.test(attr.value)) {\r\n clearList.push(attr.name);\r\n }\r\n } else if (Array.isArray(attributeRules.value)) {\r\n // if rules is an array (an array of strings - valid values)\r\n if (!attributeRules.value.includes(attr.value)) {\r\n clearList.push(attr.name);\r\n }\r\n } else if (typeof attributeRules.value === 'object') {\r\n if (\r\n Object.prototype.hasOwnProperty.call(\r\n attributeRules.value,\r\n 'preset'\r\n )\r\n ) {\r\n // if rules is preset\r\n\r\n if (\r\n Object.prototype.hasOwnProperty.call(\r\n valuesPresets,\r\n attributeRules.value.preset\r\n )\r\n ) {\r\n const presetRes = valuesPresets[\r\n attributeRules.value.preset\r\n ](attr.value);\r\n\r\n if (presetRes.remove) {\r\n clearList.push(attr.name);\r\n }\r\n } else {\r\n clearList.push(attr.name);\r\n }\r\n } else {\r\n // remove attribute if get empty object\r\n clearList.push(attr.name);\r\n }\r\n } else {\r\n // remove attribute value by default\r\n clearList.push(attr.name);\r\n }\r\n }\r\n }\r\n\r\n deleteList.forEach((attrName: string) =>\r\n tag.removeAttribute(attrName)\r\n );\r\n clearList.forEach((attrName: string) =>\r\n removeAttributeValue(tag, attrName)\r\n );\r\n } else {\r\n const deleteList: string[] = [];\r\n\r\n for (let i = 0; i < tag.attributes.length; i++) {\r\n deleteList.push(tag.attributes[i].name);\r\n }\r\n\r\n deleteList.forEach((attrName: string) =>\r\n tag.removeAttribute(attrName)\r\n );\r\n }\r\n } else {\r\n if (this.removeComments) {\r\n removeComments(tag);\r\n }\r\n\r\n tag.insertAdjacentHTML('afterend', tag.innerHTML);\r\n tag.remove();\r\n }\r\n });\r\n\r\n return parser.stringify(wrapper);\r\n }\r\n\r\n /**\r\n * Convert a string to {@link https://www.w3schools.com/html/html_entities.asp HTML Entities}.\r\n */\r\n public toHTMLEntities(str: string): string {\r\n return str\r\n .split('')\r\n .map(n => `&#${n.charCodeAt(0)};`)\r\n .join('');\r\n }\r\n}\r\n\r\n/**\r\n * Set HTML custom parser\r\n */\r\nexport const setParser = (\r\n customParser: HTMLParser | null | undefined\r\n): number => {\r\n if (!customParser) {\r\n console.error('customParser is null!');\r\n return 0;\r\n }\r\n\r\n if (!Object.prototype.hasOwnProperty.call(customParser, 'parse')) {\r\n console.error(\r\n 'cannot to find method \"parse\" in custom parser!',\r\n customParser\r\n );\r\n\r\n return 0;\r\n }\r\n\r\n if (!Object.prototype.hasOwnProperty.call(customParser, 'stringify')) {\r\n console.error(\r\n 'cannot to find method \"stringify\" in custom parser!',\r\n customParser\r\n );\r\n\r\n return 0;\r\n }\r\n\r\n parser = customParser;\r\n return 1;\r\n};\r\n\r\nexport default PurifyHTML;\r\n"],"names":["getDefaultParser","elem","string","removeAttributeValue","node","attributeName","removeComments","childIndex","getSortedByMaxChildDeep","markDeep","d","n","a","b","el","transformAttributes","rule","res","attr","safelyGetLink","str","e","deepClone","item","arrItem","key","copyConfig","config","valuesPresets","url","parser","PurifyHTML","allowedTags","__publicField","acc","curr","wrapper","tag","name","tagConfig","deleteList","clearList","attributeRules","attrRule","attrName","i","setParser","customParser"],"mappings":"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"} \ No newline at end of file diff --git a/dist/index.umd.js b/dist/index.umd.js index 37716c5..d215898 100644 --- a/dist/index.umd.js +++ b/dist/index.umd.js @@ -1,5 +1,5 @@ -(function(a,p){typeof exports=="object"&&typeof module<"u"?p(exports):typeof define=="function"&&define.amd?define(["exports"],p):(a=typeof globalThis<"u"?globalThis:a||self,p(a.PurifyHTML={}))})(this,function(a){"use strict";const p=()=>{if(globalThis.DOMParser===void 0)throw`globalThis.DOMParser is not defined! +(function(o,i){typeof exports=="object"&&typeof module!="undefined"?i(exports):typeof define=="function"&&define.amd?define(["exports"],i):(o=typeof globalThis!="undefined"?globalThis:o||self,i(o.PurifyHTML={}))})(this,function(o){"use strict";var S=Object.defineProperty;var C=(o,i,c)=>i in o?S(o,i,{enumerable:!0,configurable:!0,writable:!0,value:c}):o[i]=c;var v=(o,i,c)=>(C(o,typeof i!="symbol"?i+"":i,c),c);const i=()=>{if(globalThis.DOMParser===void 0)throw`globalThis.DOMParser is not defined! It seems that you use purify-html in node environment. For node environment you need to add HTML parser by yourself. -See https://github.com/oleksandr-dukhovnyy/purify-html?tab=readme-ov-file#node-js for details.`;const e=new DOMParser().parseFromString("","text/html").querySelector("body");return{parse(t){return e.innerHTML=t,e},stringify(t){return t.innerHTML}}},O=(e,t)=>e.setAttribute(t,""),m=e=>{if("childNodes"in e)for(let t=e.childNodes.length-1;t>0;t--)e.childNodes[t].nodeType===8&&e.childNodes[t].remove();else return!1},j=(()=>{const e=(t,r=0)=>{if(t._d=r,t.children.length)[...t.children].forEach(i=>e(i,r+1));else return r};return t=>(e(t),[...t.querySelectorAll("*")].sort((r,i)=>i._d-r._d).map(r=>(delete r._d,r)))})(),T=e=>{const t=[];return Object.prototype.hasOwnProperty.call(e,"attributes")||(e.attributes=[]),e.attributes.forEach(r=>{switch(typeof r){case"string":t.push({name:r});break;case"object":t.push(r);break}}),e.attributes=t,e},u=e=>{try{return new URL(e)}catch{return null}},v=e=>{if(typeof e=="string")return e;if(Array.isArray(e))return e.map(t=>v(t));if(typeof e=="object"&&e!==null){const t={};for(const r in e)e[r]instanceof RegExp?t[r]=e[r]:typeof e[r]=="object"?t[r]=v(e[r]):t[r]=e[r];return t}return e},L=e=>e.map(v),b={"%correct-link%"(e){return console.warn("Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4"),{remove:u(e)===null}},"%http-link%"(e){console.warn("Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4");const t=u(e);return{remove:t===null||t.protocol!=="http:"}},"%https-link%"(e){console.warn("Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4");const t=u(e);return{remove:t===null||t.protocol!=="https:"}},"%ftp-link%"(e){console.warn("Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4");const t=u(e);return{remove:t===null||t.protocol!=="ftp:"}},"%https-link-without-search-params%"(e){console.warn("Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4");const t=u(e);return{remove:t===null||t.search!==""||t.protocol!=="https:"}},"%http-link-without-search-params%"(e){console.warn("Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4");const t=u(e);return{remove:t===null||t.search!==""||t.protocol!=="http:"}},"%same-origin%"(e){console.warn("Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4");const t=u(e);return{remove:t===null||globalThis.location.origin!==t.origin}}};let f;class y{removeComments=!0;allowedTags={};whiteList;constructor(t=[]){f||(f=p()),this.allowedTags=L(t).reduce((r,i)=>{switch(typeof i){case"string":{i==="#comments"?this.removeComments=!1:r[i]=Object.assign(r[i]||{},{});break}case"object":r[i.name]=Object.assign(r[i.name]||{},T(i))}return r},{}),this.whiteList=Object.keys(this.allowedTags),this.sanitize.bind(this)}sanitize(t){const r=f.parse(t);return this.removeComments&&m(r),j(r).forEach(l=>{const w=l.tagName.toLowerCase();if(this.whiteList.includes(w)){const h=this.allowedTags[w];if(this.removeComments&&h.dontRemoveComments!==!0&&m(l),Object.prototype.hasOwnProperty.call(h,"attributes")&&h.attributes.length>0){const d=[],s=[];for(let c=0;cg.name===n.name);o?Object.prototype.hasOwnProperty.call(o,"value")&&(typeof o.value=="string"?n.value!==o.value&&s.push(n.name):typeof o.value=="function"?o.value(n.value)||s.push(n.name):o.value instanceof RegExp?o.value.test(n.value)||s.push(n.name):Array.isArray(o.value)?o.value.includes(n.value)||s.push(n.name):typeof o.value=="object"&&Object.prototype.hasOwnProperty.call(o.value,"preset")&&Object.prototype.hasOwnProperty.call(b,o.value.preset)?b[o.value.preset](n.value).remove&&s.push(n.name):s.push(n.name)):d.push(n.name)}d.forEach(c=>l.removeAttribute(c)),s.forEach(c=>O(l,c))}else{const d=[];for(let s=0;sl.removeAttribute(s))}}else this.removeComments&&m(l),l.insertAdjacentHTML("afterend",l.innerHTML),l.remove()}),f.stringify(r)}toHTMLEntities(t){return t.split("").map(r=>`&#${r.charCodeAt(0)};`).join("")}}const k=e=>e?Object.prototype.hasOwnProperty.call(e,"parse")?Object.prototype.hasOwnProperty.call(e,"stringify")?(f=e,1):(console.error('cannot to find method "stringify" in custom parser!',e),0):(console.error('cannot to find method "parse" in custom parser!',e),0):(console.error("customParser is null!"),0);a.default=y,a.sanitizer=y,a.setParser=k,Object.defineProperties(a,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}); +See https://github.com/oleksandr-dukhovnyy/purify-html?tab=readme-ov-file#node-js for details.`;const e=new DOMParser().parseFromString("","text/html").querySelector("body");return{parse(t){return e.innerHTML=t,e},stringify(t){return t.innerHTML}}},c=(e,t)=>e.setAttribute(t,""),b=e=>{if("childNodes"in e)for(let t=e.childNodes.length-1;t>0;t--)e.childNodes[t].nodeType===8&&e.childNodes[t].remove();else return!1},T=(()=>{const e=(t,r=0)=>{if(t._d=r,t.children.length)[...t.children].forEach(u=>e(u,r+1));else return r};return t=>(e(t),[...t.querySelectorAll("*")].sort((r,u)=>u._d-r._d).map(r=>(delete r._d,r)))})(),L=e=>{const t=[];return Object.prototype.hasOwnProperty.call(e,"attributes")||(e.attributes=[]),e.attributes.forEach(r=>{switch(typeof r){case"string":t.push({name:r});break;case"object":t.push(r);break}}),e.attributes=t,e},p=e=>{try{return new URL(e)}catch(t){return null}},y=e=>{if(typeof e=="string")return e;if(Array.isArray(e))return e.map(t=>y(t));if(typeof e=="object"&&e!==null){const t={};for(const r in e)e[r]instanceof RegExp?t[r]=e[r]:typeof e[r]=="object"?t[r]=y(e[r]):t[r]=e[r];return t}return e},k=e=>e.map(y),w={"%correct-link%"(e){return console.warn("Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4"),{remove:p(e)===null}},"%http-link%"(e){console.warn("Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4");const t=p(e);return{remove:t===null||t.protocol!=="http:"}},"%https-link%"(e){console.warn("Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4");const t=p(e);return{remove:t===null||t.protocol!=="https:"}},"%ftp-link%"(e){console.warn("Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4");const t=p(e);return{remove:t===null||t.protocol!=="ftp:"}},"%https-link-without-search-params%"(e){console.warn("Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4");const t=p(e);return{remove:t===null||t.search!==""||t.protocol!=="https:"}},"%http-link-without-search-params%"(e){console.warn("Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4");const t=p(e);return{remove:t===null||t.search!==""||t.protocol!=="http:"}},"%same-origin%"(e){console.warn("Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4");const t=p(e);return{remove:t===null||globalThis.location.origin!==t.origin}}};let d;class g{constructor(t=[]){v(this,"removeComments",!0);v(this,"allowedTags",{});v(this,"whiteList");d||(d=i()),this.allowedTags=k(t).reduce((r,u)=>{switch(typeof u){case"string":{u==="#comments"?this.removeComments=!1:r[u]=Object.assign(r[u]||{},{});break}case"object":r[u.name]=Object.assign(r[u.name]||{},L(u))}return r},{}),this.whiteList=Object.keys(this.allowedTags),this.sanitize.bind(this)}sanitize(t){const r=d.parse(t);return this.removeComments&&b(r),T(r).forEach(a=>{const O=a.tagName.toLowerCase();if(this.whiteList.includes(O)){const m=this.allowedTags[O];if(this.removeComments&&m.dontRemoveComments!==!0&&b(a),Object.prototype.hasOwnProperty.call(m,"attributes")&&m.attributes.length>0){const h=[],s=[];for(let f=0;fj.name===n.name);l?Object.prototype.hasOwnProperty.call(l,"value")&&(typeof l.value=="string"?n.value!==l.value&&s.push(n.name):typeof l.value=="function"?l.value(n.value)||s.push(n.name):l.value instanceof RegExp?l.value.test(n.value)||s.push(n.name):Array.isArray(l.value)?l.value.includes(n.value)||s.push(n.name):typeof l.value=="object"&&Object.prototype.hasOwnProperty.call(l.value,"preset")&&Object.prototype.hasOwnProperty.call(w,l.value.preset)?w[l.value.preset](n.value).remove&&s.push(n.name):s.push(n.name)):h.push(n.name)}h.forEach(f=>a.removeAttribute(f)),s.forEach(f=>c(a,f))}else{const h=[];for(let s=0;sa.removeAttribute(s))}}else this.removeComments&&b(a),a.insertAdjacentHTML("afterend",a.innerHTML),a.remove()}),d.stringify(r)}toHTMLEntities(t){return t.split("").map(r=>`&#${r.charCodeAt(0)};`).join("")}}const M=e=>e?Object.prototype.hasOwnProperty.call(e,"parse")?Object.prototype.hasOwnProperty.call(e,"stringify")?(d=e,1):(console.error('cannot to find method "stringify" in custom parser!',e),0):(console.error('cannot to find method "parse" in custom parser!',e),0):(console.error("customParser is null!"),0);o.default=g,o.sanitizer=g,o.setParser=M,Object.defineProperties(o,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}); //# sourceMappingURL=index.umd.js.map diff --git a/dist/index.umd.js.map b/dist/index.umd.js.map index 10649da..08fef2b 100644 --- a/dist/index.umd.js.map +++ b/dist/index.umd.js.map @@ -1 +1 @@ -{"version":3,"file":"index.umd.js","sources":["../src/utils.ts","../src/core.ts"],"sourcesContent":["/** @module utils */\r\nimport {\r\n AttributeRule,\r\n TagRule,\r\n presetTestResult,\r\n MarkedElement,\r\n HTMLParser,\r\n} from './types';\r\n\r\n/**\r\n * Setup default parser\r\n */\r\nexport const getDefaultParser = (): HTMLParser => {\r\n if (globalThis.DOMParser === undefined) {\r\n throw 'globalThis.DOMParser is not defined!\\nIt seems that you use purify-html in node environment.\\nFor node environment you need to add HTML parser by yourself.\\nSee https://github.com/oleksandr-dukhovnyy/purify-html?tab=readme-ov-file#node-js for details.';\r\n }\r\n\r\n const elem: Element = new DOMParser()\r\n .parseFromString('', 'text/html')\r\n .querySelector('body');\r\n\r\n return {\r\n parse(string: string): Element {\r\n elem.innerHTML = string;\r\n return elem;\r\n },\r\n stringify(elem: Element): string {\r\n return elem.innerHTML;\r\n },\r\n };\r\n};\r\n\r\n/**\r\n * Remove attribute value, but dont remove attribute.\r\n */\r\nexport const removeAttributeValue = (node: Element, attributeName: string) =>\r\n node.setAttribute(attributeName, '');\r\n\r\n/**\r\n * Remove all comments in childNodes.\r\n * Comments in child nodes are not removed\r\n *\r\n * @param {HTMLElement} node\r\n * @returns {undefined | false} undefined - ok, false - error\r\n */\r\nexport const removeComments = (node: Element): undefined | false => {\r\n if ('childNodes' in node) {\r\n for (\r\n let childIndex = node.childNodes.length - 1;\r\n childIndex > 0;\r\n childIndex--\r\n ) {\r\n if (node.childNodes[childIndex].nodeType === 8) {\r\n node.childNodes[childIndex].remove();\r\n }\r\n }\r\n } else {\r\n return false;\r\n }\r\n};\r\n\r\n/**\r\n * @param {Element} node\r\n * @returns {Element[]} array of node childs sorted by child's max deep\r\n */\r\nexport const getSortedByMaxChildDeep = (() => {\r\n const markDeep = (node: MarkedElement, d = 0): number | undefined => {\r\n node._d = d;\r\n\r\n if (node.children.length) {\r\n [...node.children].forEach(n => markDeep(n, d + 1));\r\n } else {\r\n return d;\r\n }\r\n };\r\n\r\n return (node: Element): Element[] => {\r\n markDeep(node);\r\n\r\n return [...node.querySelectorAll('*')]\r\n .sort((a: MarkedElement, b: MarkedElement) => b._d - a._d)\r\n .map((el: MarkedElement): Element => {\r\n delete el._d;\r\n\r\n return el;\r\n });\r\n };\r\n})();\r\n\r\n/**\r\n * Normalize a TagRule.\r\n */\r\nexport const transformAttributes = (rule: TagRule): TagRule => {\r\n const res: AttributeRule[] = [];\r\n\r\n if (!Object.prototype.hasOwnProperty.call(rule, 'attributes')) {\r\n rule.attributes = [];\r\n }\r\n\r\n rule.attributes.forEach(attr => {\r\n switch (typeof attr) {\r\n case 'string':\r\n res.push({ name: attr });\r\n break;\r\n\r\n case 'object':\r\n res.push(attr);\r\n break;\r\n }\r\n });\r\n\r\n rule.attributes = res;\r\n\r\n return rule;\r\n};\r\n\r\n/**\r\n * Safely get link with try...catch.\r\n */\r\nexport const safelyGetLink = (str: string): URL | null => {\r\n try {\r\n return new URL(str);\r\n } catch (e) {\r\n return null;\r\n }\r\n};\r\n\r\n/**\r\n * Add prefix by check\r\n *\r\n * @returns {string} if check returns true - prefix + str, else str\r\n */\r\nexport const addPrefix = (str: string, check: RegExp, prefix: string) =>\r\n check.test(str) ? str : prefix + str;\r\n\r\n/**\r\n * Deep clone an object\r\n */\r\nexport const deepClone = (item: T): T => {\r\n if (typeof item === 'string') return item;\r\n if (Array.isArray(item))\r\n return item.map(arrItem => deepClone(arrItem)) as unknown as T;\r\n\r\n if (typeof item === 'object' && item !== null) {\r\n const res: Record = {};\r\n\r\n for (const key in item) {\r\n if (item[key] instanceof RegExp) {\r\n res[key] = item[key];\r\n } else if (typeof item[key] === 'object') {\r\n res[key] = deepClone(item[key]);\r\n } else {\r\n res[key] = item[key];\r\n }\r\n }\r\n\r\n return res as T;\r\n }\r\n\r\n return item;\r\n};\r\n\r\n/**\r\n * Create clone of config for safe mutations\r\n *\r\n * @param {string[] | TagRule[]} config\r\n * @returns {string[] | TagRule[]} cloned config\r\n */\r\nexport const copyConfig = (\r\n config: (string | TagRule)[]\r\n): (string | TagRule)[] => config.map(deepClone);\r\n\r\n/**\r\n * @typedef PresetCheckResult\r\n * @type {object}\r\n * @property {boolean} remove if true - attribute value is incorrect\r\n */\r\n\r\n/**\r\n * Interface for presets.\r\n *\r\n * @interface\r\n */\r\nexport const valuesPresets = {\r\n /**\r\n * Check is str a correct link\r\n */\r\n '%correct-link%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n return {\r\n remove: safelyGetLink(str) === null,\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has HTTP protocol\r\n */\r\n '%http-link%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.protocol !== 'http:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has HTTPS protocol\r\n */\r\n '%https-link%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.protocol !== 'https:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has FTP protocol\r\n */\r\n '%ftp-link%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.protocol !== 'ftp:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has HTTPS protocol and does not have a params\r\n *\r\n * @function\r\n */\r\n '%https-link-without-search-params%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.search !== '' || url.protocol !== 'https:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has HTTP protocol and does not have a params\r\n */\r\n '%http-link-without-search-params%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.search !== '' || url.protocol !== 'http:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has same origin with current `location.origin`\r\n */\r\n '%same-origin%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || globalThis.location.origin !== url.origin,\r\n };\r\n },\r\n};\r\n","/** @module core */\r\nimport { TagRule, AttributeRule, HTMLParser } from './types';\r\n\r\nimport {\r\n removeAttributeValue,\r\n transformAttributes,\r\n valuesPresets,\r\n getSortedByMaxChildDeep,\r\n copyConfig,\r\n removeComments,\r\n getDefaultParser,\r\n} from './utils';\r\n\r\nlet parser: HTMLParser | undefined;\r\n\r\n/**\r\n * Purify instance.\r\n */\r\nexport class PurifyHTML {\r\n /**\r\n * Create PurifyHTML instance\r\n */\r\n\r\n /**\r\n * Is need to remove comments in root and in all nodes by default\r\n */\r\n protected removeComments = true;\r\n protected allowedTags: { [key: string]: TagRule } = {};\r\n protected whiteList: string[];\r\n\r\n constructor(allowedTags: TagRule[] | string[] = []) {\r\n // setup default parser\r\n if (!parser) {\r\n parser = getDefaultParser();\r\n }\r\n\r\n /**\r\n * Copy and compile a rules\r\n */\r\n this.allowedTags = copyConfig(allowedTags).reduce(\r\n (acc: object, curr: TagRule | string) => {\r\n switch (typeof curr) {\r\n case 'string': {\r\n if (curr === '#comments') {\r\n this.removeComments = false;\r\n } else {\r\n acc[curr] = Object.assign(acc[curr] || {}, {});\r\n }\r\n\r\n break;\r\n }\r\n case 'object':\r\n acc[curr.name] = Object.assign(\r\n acc[curr.name] || {},\r\n transformAttributes(curr)\r\n );\r\n }\r\n\r\n return acc;\r\n },\r\n {}\r\n );\r\n\r\n /**\r\n * Copy and compile a rules\r\n */\r\n this.whiteList = Object.keys(this.allowedTags);\r\n\r\n /**\r\n * Bind context for method sanitize\r\n */\r\n this.sanitize.bind(this);\r\n }\r\n\r\n /**\r\n * Sanitize a string.\r\n * @param {string} str to needs to sanitize.\r\n * @return {string} A string cleared according to the rules from this.allowedTags.\r\n */\r\n public sanitize(str: string): string {\r\n const wrapper: Element = parser.parse(str);\r\n\r\n if (this.removeComments) {\r\n removeComments(wrapper);\r\n }\r\n\r\n const allItems: Element[] = getSortedByMaxChildDeep(wrapper);\r\n\r\n allItems.forEach((tag: Element) => {\r\n const name = tag.tagName.toLowerCase();\r\n\r\n if (this.whiteList.includes(name)) {\r\n const tagConfig: TagRule = this.allowedTags[name];\r\n\r\n if (this.removeComments && tagConfig.dontRemoveComments !== true) {\r\n removeComments(tag);\r\n }\r\n\r\n if (\r\n Object.prototype.hasOwnProperty.call(tagConfig, 'attributes') &&\r\n tagConfig.attributes.length > 0\r\n ) {\r\n const deleteList: string[] = [];\r\n const clearList: string[] = [];\r\n\r\n for (let i = 0; i < tag.attributes.length; i++) {\r\n const attr: Attr = tag.attributes[i];\r\n\r\n // get attribute rules\r\n const attributeRules = tagConfig.attributes.find(\r\n (attrRule: AttributeRule) => attrRule.name === attr.name\r\n );\r\n\r\n if (!attributeRules) {\r\n // if rules not defined\r\n deleteList.push(attr.name);\r\n } else if (\r\n Object.prototype.hasOwnProperty.call(attributeRules, 'value')\r\n ) {\r\n // if rules defined\r\n if (typeof attributeRules.value === 'string') {\r\n if (attr.value !== attributeRules.value) {\r\n // if rules is string\r\n clearList.push(attr.name);\r\n }\r\n } else if (typeof attributeRules.value === 'function') {\r\n if (!attributeRules.value(attr.value)) {\r\n clearList.push(attr.name);\r\n }\r\n } else if (attributeRules.value instanceof RegExp) {\r\n // if rules is regexp\r\n if (!attributeRules.value.test(attr.value)) {\r\n clearList.push(attr.name);\r\n }\r\n } else if (Array.isArray(attributeRules.value)) {\r\n // if rules is an array (an array of strings - valid values)\r\n if (!attributeRules.value.includes(attr.value)) {\r\n clearList.push(attr.name);\r\n }\r\n } else if (typeof attributeRules.value === 'object') {\r\n if (\r\n Object.prototype.hasOwnProperty.call(\r\n attributeRules.value,\r\n 'preset'\r\n )\r\n ) {\r\n // if rules is preset\r\n\r\n if (\r\n Object.prototype.hasOwnProperty.call(\r\n valuesPresets,\r\n attributeRules.value.preset\r\n )\r\n ) {\r\n const presetRes = valuesPresets[\r\n attributeRules.value.preset\r\n ](attr.value);\r\n\r\n if (presetRes.remove) {\r\n clearList.push(attr.name);\r\n }\r\n } else {\r\n clearList.push(attr.name);\r\n }\r\n } else {\r\n // remove attribute if get empty object\r\n clearList.push(attr.name);\r\n }\r\n } else {\r\n // remove attribute value by default\r\n clearList.push(attr.name);\r\n }\r\n }\r\n }\r\n\r\n deleteList.forEach((attrName: string) =>\r\n tag.removeAttribute(attrName)\r\n );\r\n clearList.forEach((attrName: string) =>\r\n removeAttributeValue(tag, attrName)\r\n );\r\n } else {\r\n const deleteList: string[] = [];\r\n\r\n for (let i = 0; i < tag.attributes.length; i++) {\r\n deleteList.push(tag.attributes[i].name);\r\n }\r\n\r\n deleteList.forEach((attrName: string) =>\r\n tag.removeAttribute(attrName)\r\n );\r\n }\r\n } else {\r\n if (this.removeComments) {\r\n removeComments(tag);\r\n }\r\n\r\n tag.insertAdjacentHTML('afterend', tag.innerHTML);\r\n tag.remove();\r\n }\r\n });\r\n\r\n return parser.stringify(wrapper);\r\n }\r\n\r\n /**\r\n * Convert a string to {@link https://www.w3schools.com/html/html_entities.asp HTML Entities}.\r\n */\r\n public toHTMLEntities(str: string): string {\r\n return str\r\n .split('')\r\n .map(n => `&#${n.charCodeAt(0)};`)\r\n .join('');\r\n }\r\n}\r\n\r\n/**\r\n * Set HTML custom parser\r\n */\r\nexport const setParser = (\r\n customParser: HTMLParser | null | undefined\r\n): number => {\r\n if (!customParser) {\r\n console.error('customParser is null!');\r\n return 0;\r\n }\r\n\r\n if (!Object.prototype.hasOwnProperty.call(customParser, 'parse')) {\r\n console.error(\r\n 'cannot to find method \"parse\" in custom parser!',\r\n customParser\r\n );\r\n\r\n return 0;\r\n }\r\n\r\n if (!Object.prototype.hasOwnProperty.call(customParser, 'stringify')) {\r\n console.error(\r\n 'cannot to find method \"stringify\" in custom parser!',\r\n customParser\r\n );\r\n\r\n return 0;\r\n }\r\n\r\n parser = customParser;\r\n return 1;\r\n};\r\n\r\nexport default PurifyHTML;\r\n"],"names":["getDefaultParser","elem","string","removeAttributeValue","node","attributeName","removeComments","childIndex","getSortedByMaxChildDeep","markDeep","d","n","a","b","el","transformAttributes","rule","res","attr","safelyGetLink","str","deepClone","item","arrItem","key","copyConfig","config","valuesPresets","url","parser","PurifyHTML","allowedTags","acc","curr","wrapper","tag","name","tagConfig","deleteList","clearList","i","attributeRules","attrRule","attrName","setParser","customParser"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.umd.js","sources":["../src/utils.ts","../src/core.ts"],"sourcesContent":["/** @module utils */\r\nimport {\r\n AttributeRule,\r\n TagRule,\r\n presetTestResult,\r\n MarkedElement,\r\n HTMLParser,\r\n} from './types';\r\n\r\n/**\r\n * Setup default parser\r\n */\r\nexport const getDefaultParser = (): HTMLParser => {\r\n if (globalThis.DOMParser === undefined) {\r\n throw 'globalThis.DOMParser is not defined!\\nIt seems that you use purify-html in node environment.\\nFor node environment you need to add HTML parser by yourself.\\nSee https://github.com/oleksandr-dukhovnyy/purify-html?tab=readme-ov-file#node-js for details.';\r\n }\r\n\r\n const elem: Element = new DOMParser()\r\n .parseFromString('', 'text/html')\r\n .querySelector('body');\r\n\r\n return {\r\n parse(string: string): Element {\r\n elem.innerHTML = string;\r\n return elem;\r\n },\r\n stringify(elem: Element): string {\r\n return elem.innerHTML;\r\n },\r\n };\r\n};\r\n\r\n/**\r\n * Remove attribute value, but dont remove attribute.\r\n */\r\nexport const removeAttributeValue = (node: Element, attributeName: string) =>\r\n node.setAttribute(attributeName, '');\r\n\r\n/**\r\n * Remove all comments in childNodes.\r\n * Comments in child nodes are not removed\r\n *\r\n * @param {HTMLElement} node\r\n * @returns {undefined | false} undefined - ok, false - error\r\n */\r\nexport const removeComments = (node: Element): undefined | false => {\r\n if ('childNodes' in node) {\r\n for (\r\n let childIndex = node.childNodes.length - 1;\r\n childIndex > 0;\r\n childIndex--\r\n ) {\r\n if (node.childNodes[childIndex].nodeType === 8) {\r\n node.childNodes[childIndex].remove();\r\n }\r\n }\r\n } else {\r\n return false;\r\n }\r\n};\r\n\r\n/**\r\n * @param {Element} node\r\n * @returns {Element[]} array of node childs sorted by child's max deep\r\n */\r\nexport const getSortedByMaxChildDeep = (() => {\r\n const markDeep = (node: MarkedElement, d = 0): number | undefined => {\r\n node._d = d;\r\n\r\n if (node.children.length) {\r\n [...node.children].forEach(n => markDeep(n, d + 1));\r\n } else {\r\n return d;\r\n }\r\n };\r\n\r\n return (node: Element): Element[] => {\r\n markDeep(node);\r\n\r\n return [...node.querySelectorAll('*')]\r\n .sort((a: MarkedElement, b: MarkedElement) => b._d - a._d)\r\n .map((el: MarkedElement): Element => {\r\n delete el._d;\r\n\r\n return el;\r\n });\r\n };\r\n})();\r\n\r\n/**\r\n * Normalize a TagRule.\r\n */\r\nexport const transformAttributes = (rule: TagRule): TagRule => {\r\n const res: AttributeRule[] = [];\r\n\r\n if (!Object.prototype.hasOwnProperty.call(rule, 'attributes')) {\r\n rule.attributes = [];\r\n }\r\n\r\n rule.attributes.forEach(attr => {\r\n switch (typeof attr) {\r\n case 'string':\r\n res.push({ name: attr });\r\n break;\r\n\r\n case 'object':\r\n res.push(attr);\r\n break;\r\n }\r\n });\r\n\r\n rule.attributes = res;\r\n\r\n return rule;\r\n};\r\n\r\n/**\r\n * Safely get link with try...catch.\r\n */\r\nexport const safelyGetLink = (str: string): URL | null => {\r\n try {\r\n return new URL(str);\r\n } catch (e) {\r\n return null;\r\n }\r\n};\r\n\r\n/**\r\n * Add prefix by check\r\n *\r\n * @returns {string} if check returns true - prefix + str, else str\r\n */\r\nexport const addPrefix = (str: string, check: RegExp, prefix: string) =>\r\n check.test(str) ? str : prefix + str;\r\n\r\n/**\r\n * Deep clone an object\r\n */\r\nexport const deepClone = (item: T): T => {\r\n if (typeof item === 'string') return item;\r\n if (Array.isArray(item))\r\n return item.map(arrItem => deepClone(arrItem)) as unknown as T;\r\n\r\n if (typeof item === 'object' && item !== null) {\r\n const res: Record = {};\r\n\r\n for (const key in item) {\r\n if (item[key] instanceof RegExp) {\r\n res[key] = item[key];\r\n } else if (typeof item[key] === 'object') {\r\n res[key] = deepClone(item[key]);\r\n } else {\r\n res[key] = item[key];\r\n }\r\n }\r\n\r\n return res as T;\r\n }\r\n\r\n return item;\r\n};\r\n\r\n/**\r\n * Create clone of config for safe mutations\r\n *\r\n * @param {string[] | TagRule[]} config\r\n * @returns {string[] | TagRule[]} cloned config\r\n */\r\nexport const copyConfig = (\r\n config: (string | TagRule)[]\r\n): (string | TagRule)[] => config.map(deepClone);\r\n\r\n/**\r\n * @typedef PresetCheckResult\r\n * @type {object}\r\n * @property {boolean} remove if true - attribute value is incorrect\r\n */\r\n\r\n/**\r\n * Interface for presets.\r\n *\r\n * @interface\r\n */\r\nexport const valuesPresets = {\r\n /**\r\n * Check is str a correct link\r\n */\r\n '%correct-link%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n return {\r\n remove: safelyGetLink(str) === null,\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has HTTP protocol\r\n */\r\n '%http-link%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.protocol !== 'http:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has HTTPS protocol\r\n */\r\n '%https-link%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.protocol !== 'https:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has FTP protocol\r\n */\r\n '%ftp-link%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.protocol !== 'ftp:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has HTTPS protocol and does not have a params\r\n *\r\n * @function\r\n */\r\n '%https-link-without-search-params%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.search !== '' || url.protocol !== 'https:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has HTTP protocol and does not have a params\r\n */\r\n '%http-link-without-search-params%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || url.search !== '' || url.protocol !== 'http:',\r\n };\r\n },\r\n\r\n /**\r\n * Check is str a correct link and has same origin with current `location.origin`\r\n */\r\n '%same-origin%'(str: string): presetTestResult {\r\n console.warn(\r\n 'Default presets is deprecated and will be removed in 2.0.0. See release notes for v1.5.4'\r\n );\r\n\r\n const url = safelyGetLink(str);\r\n\r\n return {\r\n remove: url === null || globalThis.location.origin !== url.origin,\r\n };\r\n },\r\n};\r\n","/** @module core */\r\nimport { TagRule, AttributeRule, HTMLParser } from './types';\r\n\r\nimport {\r\n removeAttributeValue,\r\n transformAttributes,\r\n valuesPresets,\r\n getSortedByMaxChildDeep,\r\n copyConfig,\r\n removeComments,\r\n getDefaultParser,\r\n} from './utils';\r\n\r\nlet parser: HTMLParser | undefined;\r\n\r\n/**\r\n * Purify instance.\r\n */\r\nexport class PurifyHTML {\r\n /**\r\n * Create PurifyHTML instance\r\n */\r\n\r\n /**\r\n * Is need to remove comments in root and in all nodes by default\r\n */\r\n protected removeComments = true;\r\n protected allowedTags: { [key: string]: TagRule } = {};\r\n protected whiteList: string[];\r\n\r\n constructor(allowedTags: TagRule[] | string[] = []) {\r\n // setup default parser\r\n if (!parser) {\r\n parser = getDefaultParser();\r\n }\r\n\r\n /**\r\n * Copy and compile a rules\r\n */\r\n this.allowedTags = copyConfig(allowedTags).reduce(\r\n (acc: object, curr: TagRule | string) => {\r\n switch (typeof curr) {\r\n case 'string': {\r\n if (curr === '#comments') {\r\n this.removeComments = false;\r\n } else {\r\n acc[curr] = Object.assign(acc[curr] || {}, {});\r\n }\r\n\r\n break;\r\n }\r\n case 'object':\r\n acc[curr.name] = Object.assign(\r\n acc[curr.name] || {},\r\n transformAttributes(curr)\r\n );\r\n }\r\n\r\n return acc;\r\n },\r\n {}\r\n );\r\n\r\n /**\r\n * Copy and compile a rules\r\n */\r\n this.whiteList = Object.keys(this.allowedTags);\r\n\r\n /**\r\n * Bind context for method sanitize\r\n */\r\n this.sanitize.bind(this);\r\n }\r\n\r\n /**\r\n * Sanitize a string.\r\n * @param {string} str to needs to sanitize.\r\n * @return {string} A string cleared according to the rules from this.allowedTags.\r\n */\r\n public sanitize(str: string): string {\r\n const wrapper: Element = parser.parse(str);\r\n\r\n if (this.removeComments) {\r\n removeComments(wrapper);\r\n }\r\n\r\n const allItems: Element[] = getSortedByMaxChildDeep(wrapper);\r\n\r\n allItems.forEach((tag: Element) => {\r\n const name = tag.tagName.toLowerCase();\r\n\r\n if (this.whiteList.includes(name)) {\r\n const tagConfig: TagRule = this.allowedTags[name];\r\n\r\n if (this.removeComments && tagConfig.dontRemoveComments !== true) {\r\n removeComments(tag);\r\n }\r\n\r\n if (\r\n Object.prototype.hasOwnProperty.call(tagConfig, 'attributes') &&\r\n tagConfig.attributes.length > 0\r\n ) {\r\n const deleteList: string[] = [];\r\n const clearList: string[] = [];\r\n\r\n for (let i = 0; i < tag.attributes.length; i++) {\r\n const attr: Attr = tag.attributes[i];\r\n\r\n // get attribute rules\r\n const attributeRules = tagConfig.attributes.find(\r\n (attrRule: AttributeRule) => attrRule.name === attr.name\r\n );\r\n\r\n if (!attributeRules) {\r\n // if rules not defined\r\n deleteList.push(attr.name);\r\n } else if (\r\n Object.prototype.hasOwnProperty.call(attributeRules, 'value')\r\n ) {\r\n // if rules defined\r\n if (typeof attributeRules.value === 'string') {\r\n if (attr.value !== attributeRules.value) {\r\n // if rules is string\r\n clearList.push(attr.name);\r\n }\r\n } else if (typeof attributeRules.value === 'function') {\r\n if (!attributeRules.value(attr.value)) {\r\n clearList.push(attr.name);\r\n }\r\n } else if (attributeRules.value instanceof RegExp) {\r\n // if rules is regexp\r\n if (!attributeRules.value.test(attr.value)) {\r\n clearList.push(attr.name);\r\n }\r\n } else if (Array.isArray(attributeRules.value)) {\r\n // if rules is an array (an array of strings - valid values)\r\n if (!attributeRules.value.includes(attr.value)) {\r\n clearList.push(attr.name);\r\n }\r\n } else if (typeof attributeRules.value === 'object') {\r\n if (\r\n Object.prototype.hasOwnProperty.call(\r\n attributeRules.value,\r\n 'preset'\r\n )\r\n ) {\r\n // if rules is preset\r\n\r\n if (\r\n Object.prototype.hasOwnProperty.call(\r\n valuesPresets,\r\n attributeRules.value.preset\r\n )\r\n ) {\r\n const presetRes = valuesPresets[\r\n attributeRules.value.preset\r\n ](attr.value);\r\n\r\n if (presetRes.remove) {\r\n clearList.push(attr.name);\r\n }\r\n } else {\r\n clearList.push(attr.name);\r\n }\r\n } else {\r\n // remove attribute if get empty object\r\n clearList.push(attr.name);\r\n }\r\n } else {\r\n // remove attribute value by default\r\n clearList.push(attr.name);\r\n }\r\n }\r\n }\r\n\r\n deleteList.forEach((attrName: string) =>\r\n tag.removeAttribute(attrName)\r\n );\r\n clearList.forEach((attrName: string) =>\r\n removeAttributeValue(tag, attrName)\r\n );\r\n } else {\r\n const deleteList: string[] = [];\r\n\r\n for (let i = 0; i < tag.attributes.length; i++) {\r\n deleteList.push(tag.attributes[i].name);\r\n }\r\n\r\n deleteList.forEach((attrName: string) =>\r\n tag.removeAttribute(attrName)\r\n );\r\n }\r\n } else {\r\n if (this.removeComments) {\r\n removeComments(tag);\r\n }\r\n\r\n tag.insertAdjacentHTML('afterend', tag.innerHTML);\r\n tag.remove();\r\n }\r\n });\r\n\r\n return parser.stringify(wrapper);\r\n }\r\n\r\n /**\r\n * Convert a string to {@link https://www.w3schools.com/html/html_entities.asp HTML Entities}.\r\n */\r\n public toHTMLEntities(str: string): string {\r\n return str\r\n .split('')\r\n .map(n => `&#${n.charCodeAt(0)};`)\r\n .join('');\r\n }\r\n}\r\n\r\n/**\r\n * Set HTML custom parser\r\n */\r\nexport const setParser = (\r\n customParser: HTMLParser | null | undefined\r\n): number => {\r\n if (!customParser) {\r\n console.error('customParser is null!');\r\n return 0;\r\n }\r\n\r\n if (!Object.prototype.hasOwnProperty.call(customParser, 'parse')) {\r\n console.error(\r\n 'cannot to find method \"parse\" in custom parser!',\r\n customParser\r\n );\r\n\r\n return 0;\r\n }\r\n\r\n if (!Object.prototype.hasOwnProperty.call(customParser, 'stringify')) {\r\n console.error(\r\n 'cannot to find method \"stringify\" in custom parser!',\r\n customParser\r\n );\r\n\r\n return 0;\r\n }\r\n\r\n parser = customParser;\r\n return 1;\r\n};\r\n\r\nexport default PurifyHTML;\r\n"],"names":["getDefaultParser","elem","string","removeAttributeValue","node","attributeName","removeComments","childIndex","getSortedByMaxChildDeep","markDeep","d","n","a","b","el","transformAttributes","rule","res","attr","safelyGetLink","str","e","deepClone","item","arrItem","key","copyConfig","config","valuesPresets","url","parser","PurifyHTML","allowedTags","__publicField","acc","curr","wrapper","tag","name","tagConfig","deleteList","clearList","i","attributeRules","attrRule","attrName","setParser","customParser"],"mappings":"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"} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 57f26d6..5414a61 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "purify-html", - "version": "1.5.4", + "version": "1.5.6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "purify-html", - "version": "1.5.4", + "version": "1.5.6", "license": "MIT", "devDependencies": { "@babel/plugin-transform-modules-commonjs": "^7.19.6", diff --git a/package.json b/package.json index d1d83a0..592319d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "purify-html", - "version": "1.5.6", + "version": "1.5.7", "description": "A minimalistic library for sanitizing strings so that they can be safely used as HTML.", "repository": { "type": "git", diff --git a/vite.config.js b/vite.config.js index 581097c..4048a5b 100644 --- a/vite.config.js +++ b/vite.config.js @@ -25,7 +25,7 @@ export default defineConfig({ fileName: format => `index.${format}.js`, }, sourcemap: true, - target: 'esnext', + target: 'es6', minify: true, }, });