@gesslar/toolkit 1.0.2 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gesslar/toolkit",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Get in, bitches, we're going toolkitting.",
5
5
  "main": "./src/index.js",
6
6
  "type": "module",
@@ -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
+ }