single-file-core 1.0.15 → 1.0.18

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": "single-file-core",
3
- "version": "1.0.15",
3
+ "version": "1.0.18",
4
4
  "description": "SingleFile Core",
5
5
  "author": "Gildas Lormeau",
6
6
  "license": "AGPL-3.0-or-later",
@@ -533,7 +533,7 @@ class Processor {
533
533
  if (!this.options.backgroundSave) {
534
534
  filename = filename.replace(/\//g, replacementCharacter);
535
535
  }
536
- if (!this.options.saveToGDrive && !this.options.saveToGitHub && !this.options.saveWithCompanion &&
536
+ if (!this.options.saveToGDrive && !this.options.saveToGitHub && !this.options.saveWithCompanion && !this.options.saveWithWebDAV &&
537
537
  ((this.options.filenameMaxLengthUnit == "bytes" && util.getContentSize(filename) > this.options.filenameMaxLength) || (filename.length > this.options.filenameMaxLength))) {
538
538
  const extensionMatch = filename.match(/(\.[^.]{3,4})$/);
539
539
  const extension = extensionMatch && extensionMatch[0] && extensionMatch[0].length > 1 ? extensionMatch[0] : "";
@@ -1016,10 +1016,14 @@ class Processor {
1016
1016
 
1017
1017
  resolveStyleAttributeURLs() {
1018
1018
  this.doc.querySelectorAll("[style]").forEach(element => {
1019
- const styleContent = element.getAttribute("style");
1020
- const declarationList = cssTree.parse(styleContent, { context: "declarationList", parseCustomProperty: true });
1021
- ProcessorHelper.resolveStylesheetURLs(declarationList, this.baseURI, this.workStyleElement);
1022
- this.styles.set(element, declarationList);
1019
+ if (this.options.blockStylesheets) {
1020
+ element.removeAttribute("style");
1021
+ } else {
1022
+ const styleContent = element.getAttribute("style");
1023
+ const declarationList = cssTree.parse(styleContent, { context: "declarationList", parseCustomProperty: true });
1024
+ ProcessorHelper.resolveStylesheetURLs(declarationList, this.baseURI, this.workStyleElement);
1025
+ this.styles.set(element, declarationList);
1026
+ }
1023
1027
  });
1024
1028
  }
1025
1029
 
@@ -1030,10 +1034,11 @@ class Processor {
1030
1034
  if (element.media) {
1031
1035
  mediaText = element.media.toLowerCase();
1032
1036
  }
1033
- const stylesheetInfo = { mediaText };
1034
- if (element.closest("[" + SHADOWROOT_ATTRIBUTE_NAME + "]")) {
1035
- stylesheetInfo.scoped = true;
1036
- }
1037
+ const scoped = Boolean(element.closest("[" + SHADOWROOT_ATTRIBUTE_NAME + "]"));
1038
+ const stylesheetInfo = {
1039
+ mediaText,
1040
+ scoped
1041
+ };
1037
1042
  if (element.tagName == "LINK" && element.charset) {
1038
1043
  options.charset = element.charset;
1039
1044
  }
@@ -1043,32 +1048,19 @@ class Processor {
1043
1048
  const newResources = Object.keys(this.options.updatedResources).filter(url => this.options.updatedResources[url].type == "stylesheet" && !this.options.updatedResources[url].retrieved).map(url => this.options.updatedResources[url]);
1044
1049
  await Promise.all(newResources.map(async resource => {
1045
1050
  resource.retrieved = true;
1046
- const stylesheetInfo = {};
1047
- const element = this.doc.createElement("style");
1048
- this.doc.body.appendChild(element);
1049
- element.textContent = resource.content;
1050
- await processElement(element, stylesheetInfo, this.stylesheets, this.baseURI, this.options, this.workStyleElement);
1051
+ if (!this.options.blockStylesheets) {
1052
+ const stylesheetInfo = {};
1053
+ const element = this.doc.createElement("style");
1054
+ this.doc.body.appendChild(element);
1055
+ element.textContent = resource.content;
1056
+ await processElement(element, stylesheetInfo, this.stylesheets, this.baseURI, this.options, this.workStyleElement);
1057
+ }
1051
1058
  }));
1052
1059
  }
1053
1060
 
1054
1061
  async function processElement(element, stylesheetInfo, stylesheets, baseURI, options, workStyleElement) {
1055
1062
  let stylesheet;
1056
1063
  stylesheets.set(element, stylesheetInfo);
1057
- if (!options.blockStylesheets) {
1058
- stylesheet = await getStylesheet(element, baseURI, options, workStyleElement);
1059
- }
1060
- if (stylesheet && stylesheet.children) {
1061
- if (options.compressCSS) {
1062
- ProcessorHelper.removeSingleLineCssComments(stylesheet);
1063
- }
1064
- stylesheetInfo.stylesheet = stylesheet;
1065
- } else {
1066
- stylesheets.delete(element);
1067
- }
1068
- }
1069
-
1070
- async function getStylesheet(element, baseURI, options, workStyleElement) {
1071
- let stylesheet;
1072
1064
  if (!options.blockStylesheets) {
1073
1065
  if (element.tagName == "LINK") {
1074
1066
  stylesheet = await ProcessorHelper.resolveLinkStylesheetURLs(element.href, baseURI, options, workStyleElement);
@@ -1080,7 +1072,14 @@ class Processor {
1080
1072
  }
1081
1073
  }
1082
1074
  }
1083
- return stylesheet;
1075
+ if (stylesheet && stylesheet.children) {
1076
+ if (options.compressCSS) {
1077
+ ProcessorHelper.removeSingleLineCssComments(stylesheet);
1078
+ }
1079
+ stylesheetInfo.stylesheet = stylesheet;
1080
+ } else {
1081
+ stylesheets.delete(element);
1082
+ }
1084
1083
  }
1085
1084
  }
1086
1085
 
@@ -1621,33 +1620,35 @@ class ProcessorHelper {
1621
1620
  const imports = getImportFunctions(stylesheet);
1622
1621
  await Promise.all(imports.map(async node => {
1623
1622
  const urlNode = cssTree.find(node, node => node.type == "Url") || cssTree.find(node, node => node.type == "String");
1624
- let resourceURL = normalizeURL(urlNode.value);
1625
- if (!testIgnoredPath(resourceURL) && testValidPath(resourceURL)) {
1626
- urlNode.value = util.EMPTY_RESOURCE;
1627
- try {
1628
- resourceURL = util.resolveURL(resourceURL, baseURI);
1629
- } catch (error) {
1630
- // ignored
1631
- }
1632
- if (testValidURL(resourceURL) && !importedStyleSheets.has(resourceURL)) {
1633
- const content = await getStylesheetContent(resourceURL);
1634
- resourceURL = content.resourceURL;
1635
- content.data = getUpdatedResourceContent(resourceURL, content, options);
1636
- if (content.data && content.data.match(/^<!doctype /i)) {
1637
- content.data = "";
1638
- }
1639
- const mediaQueryListNode = cssTree.find(node, node => node.type == "MediaQueryList");
1640
- if (mediaQueryListNode) {
1641
- content.data = wrapMediaQuery(content.data, cssTree.generate(mediaQueryListNode));
1623
+ if (urlNode) {
1624
+ let resourceURL = normalizeURL(urlNode.value);
1625
+ if (!testIgnoredPath(resourceURL) && testValidPath(resourceURL)) {
1626
+ urlNode.value = util.EMPTY_RESOURCE;
1627
+ try {
1628
+ resourceURL = util.resolveURL(resourceURL, baseURI);
1629
+ } catch (error) {
1630
+ // ignored
1642
1631
  }
1643
- const importedStylesheet = cssTree.parse(content.data, { context: "stylesheet", parseCustomProperty: true });
1644
- const ancestorStyleSheets = new Set(importedStyleSheets);
1645
- ancestorStyleSheets.add(resourceURL);
1646
- await ProcessorHelper.resolveImportURLs(importedStylesheet, resourceURL, options, workStylesheet, ancestorStyleSheets);
1647
- for (let keyName of Object.keys(importedStylesheet)) {
1648
- node[keyName] = importedStylesheet[keyName];
1632
+ if (testValidURL(resourceURL) && !importedStyleSheets.has(resourceURL)) {
1633
+ const content = await getStylesheetContent(resourceURL);
1634
+ resourceURL = content.resourceURL;
1635
+ content.data = getUpdatedResourceContent(resourceURL, content, options);
1636
+ if (content.data && content.data.match(/^<!doctype /i)) {
1637
+ content.data = "";
1638
+ }
1639
+ const mediaQueryListNode = cssTree.find(node, node => node.type == "MediaQueryList");
1640
+ if (mediaQueryListNode) {
1641
+ content.data = wrapMediaQuery(content.data, cssTree.generate(mediaQueryListNode));
1642
+ }
1643
+ const importedStylesheet = cssTree.parse(content.data, { context: "stylesheet", parseCustomProperty: true });
1644
+ const ancestorStyleSheets = new Set(importedStyleSheets);
1645
+ ancestorStyleSheets.add(resourceURL);
1646
+ await ProcessorHelper.resolveImportURLs(importedStylesheet, resourceURL, options, workStylesheet, ancestorStyleSheets);
1647
+ for (let keyName of Object.keys(importedStylesheet)) {
1648
+ node[keyName] = importedStylesheet[keyName];
1649
+ }
1650
+ importFound = true;
1649
1651
  }
1650
- importFound = true;
1651
1652
  }
1652
1653
  }
1653
1654
  }));
@@ -1809,7 +1810,8 @@ class ProcessorHelper {
1809
1810
  let { content, indexResource, duplicate } = await batchRequest.addURL(resourceURL,
1810
1811
  { asBinary: true, expectedType: "image", groupDuplicates: options.groupDuplicateImages });
1811
1812
  if (!originalResourceURL.startsWith("#")) {
1812
- if (duplicate && options.groupDuplicateImages && util.getContentSize(content) < SINGLE_FILE_VARIABLE_MAX_SIZE) {
1813
+ const maxSizeDuplicateImages = options.maxSizeDuplicateImages || SINGLE_FILE_VARIABLE_MAX_SIZE;
1814
+ if (duplicate && options.groupDuplicateImages && util.getContentSize(content) < maxSizeDuplicateImages) {
1813
1815
  const varNode = cssTree.parse("var(" + SINGLE_FILE_VARIABLE_NAME_PREFIX + indexResource + ")", { context: "value" });
1814
1816
  for (let keyName of Object.keys(varNode.children.head.data)) {
1815
1817
  urlNode[keyName] = varNode.children.head.data[keyName];
@@ -1882,7 +1884,8 @@ class ProcessorHelper {
1882
1884
  const forbiddenPrefixFound = PREFIXES_FORBIDDEN_DATA_URI.filter(prefixDataURI => content.startsWith(prefixDataURI)).length;
1883
1885
  if (!forbiddenPrefixFound) {
1884
1886
  const isSVG = content.startsWith(PREFIX_DATA_URI_IMAGE_SVG);
1885
- if (expectedType == "image" && processDuplicates && duplicate && !isSVG && util.getContentSize(content) < SINGLE_FILE_VARIABLE_MAX_SIZE) {
1887
+ const maxSizeDuplicateImages = options.maxSizeDuplicateImages || SINGLE_FILE_VARIABLE_MAX_SIZE;
1888
+ if (expectedType == "image" && processDuplicates && duplicate && !isSVG && util.getContentSize(content) < maxSizeDuplicateImages) {
1886
1889
  if (ProcessorHelper.replaceImageSource(resourceElement, SINGLE_FILE_VARIABLE_NAME_PREFIX + indexResource, options)) {
1887
1890
  cssVariables.set(indexResource, { content, url: originURL });
1888
1891
  const declarationList = cssTree.parse(resourceElement.getAttribute("style"), { context: "declarationList", parseCustomProperty: true });
@@ -21,28 +21,4 @@
21
21
  * Source.
22
22
  */
23
23
 
24
- /* global window, globalThis */
25
-
26
- (globalThis => {
27
-
28
- const FETCH_REQUEST_EVENT = "single-file-request-fetch";
29
- const FETCH_RESPONSE_EVENT = "single-file-response-fetch";
30
-
31
- const CustomEvent = globalThis.CustomEvent;
32
- const fetch = globalThis.fetch;
33
- const addEventListener = (type, listener, options) => globalThis.addEventListener(type, listener, options);
34
- const dispatchEvent = event => { try { globalThis.dispatchEvent(event); } catch (error) { /* ignored */ } };
35
-
36
- addEventListener(FETCH_REQUEST_EVENT, async event => {
37
- const url = event.detail;
38
- let detail;
39
- try {
40
- const response = await fetch(url, { cache: "force-cache" });
41
- detail = { url, response: await response.arrayBuffer(), headers: [...response.headers], status: response.status };
42
- } catch (error) {
43
- detail = { url, error: error && error.toString() };
44
- }
45
- dispatchEvent(new CustomEvent(FETCH_RESPONSE_EVENT, { detail }));
46
- });
47
-
48
- })(typeof globalThis == "object" ? globalThis : window);
24
+ export * from "./processors/frame-tree/content/content-frame-tree.js";
@@ -0,0 +1,24 @@
1
+ /*
2
+ * Copyright 2010-2022 Gildas Lormeau
3
+ * contact : gildas.lormeau <at> gmail.com
4
+ *
5
+ * This file is part of SingleFile.
6
+ *
7
+ * The code in this file is free software: you can redistribute it and/or
8
+ * modify it under the terms of the GNU Affero General Public License
9
+ * (GNU AGPL) as published by the Free Software Foundation, either version 3
10
+ * of the License, or (at your option) any later version.
11
+ *
12
+ * The code in this file is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
15
+ * General Public License for more details.
16
+ *
17
+ * As additional permission under GNU AGPL version 3 section 7, you may
18
+ * distribute UNMODIFIED VERSIONS OF THIS file without the copy of the GNU
19
+ * AGPL normally required by section 4, provided you include this license
20
+ * notice and a URL through which recipients can access the Corresponding
21
+ * Source.
22
+ */
23
+
24
+ import "./processors/hooks/content/content-hooks-frames-web.js";
@@ -0,0 +1,24 @@
1
+ /*
2
+ * Copyright 2010-2022 Gildas Lormeau
3
+ * contact : gildas.lormeau <at> gmail.com
4
+ *
5
+ * This file is part of SingleFile.
6
+ *
7
+ * The code in this file is free software: you can redistribute it and/or
8
+ * modify it under the terms of the GNU Affero General Public License
9
+ * (GNU AGPL) as published by the Free Software Foundation, either version 3
10
+ * of the License, or (at your option) any later version.
11
+ *
12
+ * The code in this file is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
15
+ * General Public License for more details.
16
+ *
17
+ * As additional permission under GNU AGPL version 3 section 7, you may
18
+ * distribute UNMODIFIED VERSIONS OF THIS file without the copy of the GNU
19
+ * AGPL normally required by section 4, provided you include this license
20
+ * notice and a URL through which recipients can access the Corresponding
21
+ * Source.
22
+ */
23
+
24
+ import "./common/content-infobar-web.js";
File without changes