@gesslar/toolkit 1.0.3 → 1.0.4
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/package.json +1 -1
- package/src/browser/index.js +1 -0
- package/src/browser/lib/HTML.js +137 -0
- package/src/browser/lib/vendor/dompurify.esm.js +1515 -0
- package/src/lib/Contract.js +2 -2
- package/src/types/browser/index.d.ts +1 -0
- package/src/types/browser/lib/HTML.d.ts +38 -0
- package/src/types/browser/lib/HTML.d.ts.map +1 -0
- package/src/types/browser/lib/vendor/dompurify.esm.d.ts +29 -0
- package/src/types/browser/lib/vendor/dompurify.esm.d.ts.map +1 -0
- package/src/types/lib/Contract.d.ts +4 -4
- package/src/types/lib/Contract.d.ts.map +1 -1
package/package.json
CHANGED
package/src/browser/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
export {default as Collection} from "./lib/Collection.js"
|
|
5
5
|
export {default as Data} from "./lib/Data.js"
|
|
6
|
+
export {default as HTML} from "./lib/HTML.js"
|
|
6
7
|
export {default as Sass} from "./lib/Sass.js"
|
|
7
8
|
export {default as Tantrum} from "./lib/Tantrum.js"
|
|
8
9
|
export {default as Type} from "./lib/TypeSpec.js"
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import DOMPurify from "./vendor/dompurify.esm.js"
|
|
2
|
+
import Sass from "./Sass.js"
|
|
3
|
+
|
|
4
|
+
export default class HTML {
|
|
5
|
+
#domPurify
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Lightweight HTML helper utilities for browser contexts.
|
|
9
|
+
*
|
|
10
|
+
* @param {object|(() => unknown)} domPurify - Optional DOMPurify instance or factory.
|
|
11
|
+
*/
|
|
12
|
+
constructor(domPurify=DOMPurify) {
|
|
13
|
+
this.#domPurify = domPurify
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Fetches an HTML fragment and returns the contents inside the <body> tag when present.
|
|
18
|
+
*
|
|
19
|
+
* @param {string} url - Location of the HTML resource to load.
|
|
20
|
+
* @param {boolean} filterBodyContent - If true, returns only content found between the <body> tags. Defaults to false.
|
|
21
|
+
* @returns {Promise<string>} Sanitized HTML string or empty string on missing content.
|
|
22
|
+
*/
|
|
23
|
+
async loadHTML(url, filterBodyContent=false) {
|
|
24
|
+
try {
|
|
25
|
+
const response = await fetch(url)
|
|
26
|
+
const html = await response?.text()
|
|
27
|
+
|
|
28
|
+
if(!html)
|
|
29
|
+
return ""
|
|
30
|
+
|
|
31
|
+
const {body} = /<body[^>]*>(?<body>[\s\S]*?)<\/body>/i.exec(html)?.groups ?? {}
|
|
32
|
+
|
|
33
|
+
if(filterBodyContent)
|
|
34
|
+
return body ?? html
|
|
35
|
+
|
|
36
|
+
return html
|
|
37
|
+
} catch(error) {
|
|
38
|
+
throw Sass.new(`Loading HTML from '${url}'.`, error)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Sanitizes arbitrary HTML using DOMPurify.
|
|
44
|
+
*
|
|
45
|
+
* @param {string} text - HTML string to sanitize. Defaults to "".
|
|
46
|
+
* @returns {string} Sanitized HTML.
|
|
47
|
+
*/
|
|
48
|
+
sanitise(text="") {
|
|
49
|
+
const sanitizer = this.#resolveSanitizer()
|
|
50
|
+
|
|
51
|
+
return sanitizer(String(text ?? ""))
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Sanitizes an HTML string and replaces the element's children with the result.
|
|
56
|
+
*
|
|
57
|
+
* @param {Element} element - Target element to replace content within.
|
|
58
|
+
* @param {string} htmlString - HTML string to sanitize and insert.
|
|
59
|
+
*/
|
|
60
|
+
setHTMLContent(element, htmlString) {
|
|
61
|
+
if(!element)
|
|
62
|
+
throw Sass.new("setHTMLContent requires a valid element.")
|
|
63
|
+
|
|
64
|
+
const sanitised = this.sanitise(htmlString)
|
|
65
|
+
const doc = element.ownerDocument ?? globalThis.document
|
|
66
|
+
|
|
67
|
+
if(doc?.createRange && typeof element.replaceChildren === "function") {
|
|
68
|
+
const range = doc.createRange()
|
|
69
|
+
const fragment = range.createContextualFragment(sanitised)
|
|
70
|
+
|
|
71
|
+
element.replaceChildren(fragment)
|
|
72
|
+
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if("innerHTML" in element) {
|
|
77
|
+
element.innerHTML = sanitised
|
|
78
|
+
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if(typeof element.replaceChildren === "function") {
|
|
83
|
+
element.replaceChildren(sanitised)
|
|
84
|
+
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
throw Sass.new("Unable to set HTML content: unsupported element.")
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Removes all child nodes from the given element.
|
|
93
|
+
*
|
|
94
|
+
* @param {Element} element - Element to clear.
|
|
95
|
+
*/
|
|
96
|
+
clearHTMLContent(element) {
|
|
97
|
+
if(!element)
|
|
98
|
+
throw Sass.new("clearHTMLContent requires a valid element.")
|
|
99
|
+
|
|
100
|
+
if(typeof element.replaceChildren === "function") {
|
|
101
|
+
element.replaceChildren()
|
|
102
|
+
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if("innerHTML" in element) {
|
|
107
|
+
element.innerHTML = ""
|
|
108
|
+
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
throw Sass.new("Unable to clear HTML content: unsupported element.")
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Resolves the DOMPurify sanitize function.
|
|
117
|
+
*
|
|
118
|
+
* @returns {(input: string) => string} Sanitizer function.
|
|
119
|
+
*/
|
|
120
|
+
#resolveSanitizer() {
|
|
121
|
+
if(this.#domPurify?.sanitize)
|
|
122
|
+
return this.#domPurify.sanitize
|
|
123
|
+
|
|
124
|
+
if(typeof this.#domPurify === "function") {
|
|
125
|
+
try {
|
|
126
|
+
const configured = this.#domPurify(globalThis.window ?? globalThis)
|
|
127
|
+
|
|
128
|
+
if(configured?.sanitize)
|
|
129
|
+
return configured.sanitize
|
|
130
|
+
} catch(error) {
|
|
131
|
+
throw Sass.new("DOMPurify sanitization is unavailable in this environment.", error)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
throw Sass.new("DOMPurify sanitization is unavailable in this environment.")
|
|
136
|
+
}
|
|
137
|
+
}
|