single-file-core 1.5.67 → 1.5.69

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/core/index.js CHANGED
@@ -415,7 +415,6 @@ const SHADOWROOT_ATTRIBUTE_NAME = "shadowrootmode";
415
415
  const SHADOWROOT_DELEGATES_FOCUS = "shadowrootdelegatesfocus";
416
416
  const SHADOWROOT_CLONABLE = "shadowrootclonable";
417
417
  const SHADOWROOT_SERIALIZABLE = "shadowrootserializable";
418
- const SCRIPT_TEMPLATE_SHADOW_ROOT = "data-template-shadow-root";
419
418
  const SCRIPT_OPTIONS = "data-single-file-options";
420
419
  const UTF8_CHARSET = "utf-8";
421
420
 
@@ -539,15 +538,6 @@ class Processor {
539
538
  if (this.options.includeInfobar) {
540
539
  util.appendInfobar(this.doc, this.options);
541
540
  }
542
- if (this.doc.querySelector("template[" + SHADOWROOT_ATTRIBUTE_NAME + "]") || (this.options.shadowRoots && this.options.shadowRoots.length)) {
543
- if (this.options.blockScripts) {
544
- this.doc.querySelectorAll("script[" + SCRIPT_TEMPLATE_SHADOW_ROOT + "]").forEach(element => element.remove());
545
- }
546
- const scriptElement = this.doc.createElement("script");
547
- scriptElement.setAttribute(SCRIPT_TEMPLATE_SHADOW_ROOT, "");
548
- scriptElement.textContent = `(()=>{document.currentScript.remove();processNode(document);function processNode(node){node.querySelectorAll("template[${SHADOWROOT_ATTRIBUTE_NAME}]").forEach(element=>{let shadowRoot = element.parentElement.shadowRoot;if (!shadowRoot) {try {shadowRoot=element.parentElement.attachShadow({mode:element.getAttribute("${SHADOWROOT_ATTRIBUTE_NAME}"),delegatesFocus:element.getAttribute("${SHADOWROOT_DELEGATES_FOCUS}")!=null,clonable:element.getAttribute("${SHADOWROOT_CLONABLE}")!=null,serializable:element.getAttribute("${SHADOWROOT_SERIALIZABLE}")!=null});shadowRoot.innerHTML=element.innerHTML;element.remove()} catch (error) {} if (shadowRoot) {processNode(shadowRoot)}}})}})()`;
549
- this.doc.body.appendChild(scriptElement);
550
- }
551
541
  if (this.options.insertCanonicalLink && this.options.saveUrl.match(HTTP_URI_PREFIX)) {
552
542
  let canonicalLink = this.doc.querySelector("link[rel=canonical]");
553
543
  if (!canonicalLink) {
@@ -850,7 +840,7 @@ class Processor {
850
840
  element.setAttribute("src", DISABLED_SCRIPT);
851
841
  }
852
842
  });
853
- const scriptElements = this.doc.querySelectorAll("script:not([type=\"application/ld+json\"]):not([" + SCRIPT_TEMPLATE_SHADOW_ROOT + "]):not([" + SCRIPT_OPTIONS + "])");
843
+ const scriptElements = this.doc.querySelectorAll("script:not([type=\"application/ld+json\"]):not([" + SCRIPT_OPTIONS + "])");
854
844
  this.stats.set("discarded", "scripts", scriptElements.length);
855
845
  this.stats.set("processed", "scripts", scriptElements.length);
856
846
  scriptElements.forEach(element => element.remove());
@@ -896,6 +886,13 @@ class Processor {
896
886
  if (this.options.removeHiddenElements) {
897
887
  this.doc.querySelectorAll("input[type=hidden]").forEach(element => element.remove());
898
888
  }
889
+ if (this.options.removedElementsSelector) {
890
+ try {
891
+ this.doc.querySelectorAll(this.options.removedElementsSelector).forEach(element => element.remove());
892
+ } catch {
893
+ // ignored
894
+ }
895
+ }
899
896
  if (!this.options.saveFavicon) {
900
897
  this.doc.querySelectorAll("link[rel*=\"icon\"]").forEach(element => element.remove());
901
898
  }
@@ -17025,10 +17025,35 @@ async function evalTemplate(template = "", options, content, doc, context = {})
17025
17025
  },
17026
17026
  // eslint-disable-next-line no-unused-vars
17027
17027
  "stringify": value => { try { return JSON.stringify(value); } catch (error) { return value; } },
17028
- // eslint-disable-next-line no-unused-vars
17029
- "encode-base64": value => { try { return btoa(value); } catch (error) { return value; } },
17030
- // eslint-disable-next-line no-unused-vars
17031
- "decode-base64": value => { try { return atob(value); } catch (error) { return value; } },
17028
+ "encode-base64": value => {
17029
+ // can be replaced with Uint8Array.toBase64() which should already be supported by most browsers
17030
+ // function taken from https://developer.mozilla.org/en-US/docs/Web/API/Window/btoa
17031
+ function bytesToBase64(bytes) {
17032
+ const binString = Array.from(bytes, (byte) =>
17033
+ String.fromCodePoint(byte),
17034
+ ).join("");
17035
+ return btoa(binString);
17036
+ }
17037
+
17038
+ const utf8Array = new TextEncoder().encode(value);
17039
+ return bytesToBase64(utf8Array);
17040
+ },
17041
+ "decode-base64": value => {
17042
+ // can be replaced with Uint8Array.fromBase64() which should already be supported by most browsers
17043
+ // function taken from https://developer.mozilla.org/en-US/docs/Web/API/Window/btoa
17044
+ function base64ToBytes(base64) {
17045
+ const binString = atob(base64);
17046
+ return Uint8Array.from(binString, (m) => m.codePointAt(0));
17047
+ }
17048
+
17049
+ try {
17050
+ const utf8Array = base64ToBytes(value);
17051
+ return new TextDecoder("utf-8").decode(utf8Array);
17052
+ // eslint-disable-next-line no-unused-vars
17053
+ } catch(error) {
17054
+ return value;
17055
+ }
17056
+ },
17032
17057
  // eslint-disable-next-line no-unused-vars
17033
17058
  "encode-uri": value => { try { return encodeURI(value); } catch (error) { return value; } },
17034
17059
  // eslint-disable-next-line no-unused-vars
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "single-file-core",
3
- "version": "1.5.67",
3
+ "version": "1.5.69",
4
4
  "description": "SingleFile Core",
5
5
  "author": "Gildas Lormeau",
6
6
  "license": "AGPL-3.0-or-later",
@@ -27,7 +27,7 @@ export {
27
27
  extract
28
28
  };
29
29
 
30
- async function extract(content, { password, prompt = () => { }, shadowRootScriptURL, zipOptions = { useWebWorkers: false }, noBlobURL } = {}) {
30
+ async function extract(content, { password, prompt = () => { }, zipOptions = { useWebWorkers: false }, noBlobURL } = {}) {
31
31
  const KNOWN_MIMETYPES = {
32
32
  "gif": "image/gif",
33
33
  "jpg": "image/jpeg",
@@ -191,11 +191,6 @@ async function extract(content, { password, prompt = () => { }, shadowRootScript
191
191
  resource.textContent = textContent;
192
192
  resource.content = await getContent(resource);
193
193
  }
194
- if (filename.match(REGEXP_MATCH_INDEX)) {
195
- if (shadowRootScriptURL) {
196
- resource.textContent = textContent.replace(/<script data-template-shadow-root.*<\/script>/g, "<script data-template-shadow-root src=" + shadowRootScriptURL + "></" + "script>");
197
- }
198
- }
199
194
  if (filename.match(REGEXP_MATCH_ROOT_INDEX)) {
200
195
  docContent = textContent;
201
196
  url = resource.url;