1
0
Gildas 7 жил өмнө
parent
commit
367dfaf247

+ 135 - 135
lib/single-file/single-file-core.js

@@ -43,15 +43,15 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			}
 		}
 		async initialize() {
-			this.processor = new PageProcessor(this.options, true);
-			await this.processor.loadPage();
-			await this.processor.initialize();
+			this.runner = new Runner(this.options, true);
+			await this.runner.loadPage();
+			await this.runner.initialize();
 		}
 		async run() {
-			await this.processor.run();
+			await this.runner.run();
 		}
 		async getPageData() {
-			return this.processor.getPageData();
+			return this.runner.getPageData();
 		}
 	}
 
@@ -78,9 +78,9 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		}
 	}
 
-	// -------------
-	// PageProcessor
-	// -------------
+	// ------
+	// Runner
+	// ------
 	const RESOLVE_URLS_STAGE = 0;
 	const REPLACE_DATA_STAGE = 1;
 	const REPLACE_DOCS_STAGE = 2;
@@ -140,14 +140,14 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		]
 	}];
 
-	class PageProcessor {
+	class Runner {
 		constructor(options, root) {
 			this.root = root;
 			this.options = options;
 			this.options.url = this.options.url || this.options.doc.location.href;
 			this.options.baseURI = this.options.doc && this.options.doc.baseURI;
 			this.batchRequest = new BatchRequest();
-			this.processor = new DOMProcessor(options, this.batchRequest);
+			this.processor = new Processor(options, this.batchRequest);
 			if (this.options.doc) {
 				const docData = docUtil.preProcessDoc(this.options.doc, this.options.win, this.options);
 				this.options.canvasData = docData.canvasData;
@@ -297,19 +297,19 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		}
 	}
 
-	// ------------
-	// DOMProcessor
-	// ------------
+	// ---------
+	// Processor
+	// ---------
 	const EMPTY_DATA_URI = "data:base64,";
 	const EMPTY_IMAGE = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
 	const SCRIPT_TAG_FOUND = /<script/gi;
 	const NOSCRIPT_TAG_FOUND = /<noscript/gi;
 
-	class DOMProcessor {
+	class Processor {
 		constructor(options, batchRequest) {
 			this.options = options;
 			this.stats = new Stats(options);
-			this.baseURI = DomUtil.normalizeURL(options.baseURI || options.url);
+			this.baseURI = Util.normalizeURL(options.baseURI || options.url);
 			this.batchRequest = batchRequest;
 			this.stylesheets = new Map();
 			this.styles = new Map();
@@ -356,7 +356,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 				this.stats.set("processed", "HTML bytes", contentSize);
 				this.stats.add("discarded", "HTML bytes", size - contentSize);
 			}
-			let filename = await DomProcessorHelper.evalTemplate(this.options.filenameTemplate, this.options, content);
+			let filename = await ProcessorHelper.evalTemplate(this.options.filenameTemplate, this.options, content);
 			filename = filename.replace(/[~\\?%*:|"<>\x00-\x1f\x7F]+/g, "_"); // eslint-disable-line no-control-regex
 			filename = filename.replace(/\.\.\//g, "").replace(/^\/+/, "").replace(/\/+/g, "/").replace(/\/$/, "");
 			if (!this.options.backgroundSave) {
@@ -382,7 +382,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		removeUnselectedElements() {
 			const rootElement = this.doc.querySelector("[" + SELECTED_CONTENT_ROOT_ATTRIBUTE_NAME + "]");
 			if (rootElement) {
-				DomProcessorHelper.isolateElements(rootElement);
+				ProcessorHelper.isolateElements(rootElement);
 				rootElement.removeAttribute(SELECTED_CONTENT_ROOT_ATTRIBUTE_NAME);
 				rootElement.removeAttribute(SELECTED_CONTENT_ATTRIBUTE_NAME);
 			}
@@ -486,7 +486,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			const creatorElement = this.doc.querySelector("meta[name=creator]");
 			const publisherElement = this.doc.querySelector("meta[name=publisher]");
 			this.options.title = titleElement ? titleElement.textContent.trim() : "";
-			this.options.infobarContent = await DomProcessorHelper.evalTemplate(this.options.infobarTemplate, this.options, null, true);
+			this.options.infobarContent = await ProcessorHelper.evalTemplate(this.options.infobarTemplate, this.options, null, true);
 			this.options.info = {
 				description: descriptionElement ? descriptionElement.content.trim() : "",
 				lang: this.doc.documentElement.lang,
@@ -589,8 +589,8 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		resolveHrefs() {
 			this.doc.querySelectorAll("[href]").forEach(element => {
 				const href = element.getAttribute("href");
-				if (!DomUtil.testIgnoredPath(href) && DomUtil.testValidPath(href, this.baseURI, this.options.url)) {
-					const normalizedHref = DomUtil.normalizeURL(href);
+				if (!Util.testIgnoredPath(href) && Util.testValidPath(href, this.baseURI, this.options.url)) {
+					const normalizedHref = Util.normalizeURL(href);
 					if (element.tagName == "LINK") {
 						try {
 							element.setAttribute("href", docUtil.resolveURL(href, this.options.baseURI || this.options.url));
@@ -660,7 +660,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 				this.doc.querySelectorAll("canvas").forEach((canvasElement, indexCanvasElement) => {
 					const canvasData = this.options.canvasData[indexCanvasElement];
 					if (canvasData) {
-						DomProcessorHelper.setBackgroundImage(canvasElement, "url(" + canvasData.dataURI + ")");
+						ProcessorHelper.setBackgroundImage(canvasElement, "url(" + canvasData.dataURI + ")");
 						this.stats.add("processed", "canvas", 1);
 					}
 				});
@@ -750,20 +750,20 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 				["image", "xlink:href", PREFIX_DATA_URI_IMAGE]
 			];
 			let resourcePromises = processAttributeArgs.map(([selector, attributeName, prefixDataURI, processDuplicates, removeElementIfMissing]) =>
-				DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll(selector), attributeName, prefixDataURI, this.baseURI, this.options, this.cssVariables, this.styles, this.batchRequest, processDuplicates, removeElementIfMissing)
+				ProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll(selector), attributeName, prefixDataURI, this.baseURI, this.options, this.cssVariables, this.styles, this.batchRequest, processDuplicates, removeElementIfMissing)
 			);
 			resourcePromises = resourcePromises.concat([
-				DomProcessorHelper.processXLinks(this.doc.querySelectorAll("use"), this.baseURI, this.options, this.batchRequest),
-				DomProcessorHelper.processSrcset(this.doc.querySelectorAll("img[srcset], source[srcset]"), "srcset", PREFIX_DATA_URI_IMAGE, this.baseURI, this.options, this.batchRequest)
+				ProcessorHelper.processXLinks(this.doc.querySelectorAll("use"), this.baseURI, this.options, this.batchRequest),
+				ProcessorHelper.processSrcset(this.doc.querySelectorAll("img[srcset], source[srcset]"), "srcset", PREFIX_DATA_URI_IMAGE, this.baseURI, this.options, this.batchRequest)
 			]);
 			if (!this.options.removeAudioSrc) {
-				resourcePromises.push(DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("audio[src], audio > source[src]"), "src", PREFIX_DATA_URI_AUDIO, this.baseURI, this.options, this.cssVariables, this.styles, this.batchRequest));
+				resourcePromises.push(ProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("audio[src], audio > source[src]"), "src", PREFIX_DATA_URI_AUDIO, this.baseURI, this.options, this.cssVariables, this.styles, this.batchRequest));
 			}
 			if (!this.options.removeVideoSrc) {
-				resourcePromises.push(DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("video[src], video > source[src]"), "src", PREFIX_DATA_URI_VIDEO, this.baseURI, this.options, this.cssVariables, this.styles, this.batchRequest));
+				resourcePromises.push(ProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("video[src], video > source[src]"), "src", PREFIX_DATA_URI_VIDEO, this.baseURI, this.options, this.cssVariables, this.styles, this.batchRequest));
 			}
 			await Promise.all(resourcePromises);
-			DomProcessorHelper.processShortcutIcons(this.doc);
+			ProcessorHelper.processShortcutIcons(this.doc);
 		}
 
 		async resolveStylesheetURLs() {
@@ -784,9 +784,9 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 							if (element.charset) {
 								options.charset = element.charset;
 							}
-							stylesheetContent = await DomProcessorHelper.resolveLinkStylesheetURLs(element.href, this.baseURI, options);
+							stylesheetContent = await ProcessorHelper.resolveLinkStylesheetURLs(element.href, this.baseURI, options);
 						} else {
-							stylesheetContent = await DomProcessorHelper.resolveImportURLs(element.textContent, this.baseURI, options);
+							stylesheetContent = await ProcessorHelper.resolveImportURLs(element.textContent, this.baseURI, options);
 						}
 						let stylesheet;
 						try {
@@ -812,7 +812,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 
 		async processStylesheets() {
 			await Promise.all(Array.from(this.stylesheets).map(([, stylesheetInfo]) =>
-				DomProcessorHelper.processStylesheet(stylesheetInfo.stylesheet.children, this.baseURI, this.options, this.cssVariables, this.batchRequest)
+				ProcessorHelper.processStylesheet(stylesheetInfo.stylesheet.children, this.baseURI, this.options, this.cssVariables, this.batchRequest)
 			));
 		}
 
@@ -880,7 +880,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			if (this.options.framesData) {
 				const frameElements = Array.from(this.doc.querySelectorAll("iframe, frame, object[type=\"text/html\"][data]"));
 				await Promise.all(frameElements.map(async frameElement => {
-					DomProcessorHelper.setFrameEmptySrc(frameElement);
+					ProcessorHelper.setFrameEmptySrc(frameElement);
 					const frameWindowId = frameElement.getAttribute(docUtil.windowIdAttributeName(this.options.sessionId));
 					if (frameWindowId) {
 						const frameData = this.options.framesData.find(frame => frame.windowId == frameWindowId);
@@ -905,7 +905,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 					options.fontsData = frameData.fontsData;
 					options.imageData = frameData.imageData;
 					options.usedFonts = frameData.usedFonts;
-					frameData.processor = new PageProcessor(options);
+					frameData.processor = new Runner(options);
 					frameData.frameElement = frameElement;
 					await frameData.processor.loadPage();
 					await frameData.processor.initialize();
@@ -932,7 +932,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 								} else {
 									frameElement.setAttribute("sandbox", "");
 								}
-								DomProcessorHelper.setFrameContent(frameElement, pageData.content);
+								ProcessorHelper.setFrameContent(frameElement, pageData.content);
 								this.stats.addAll(pageData);
 							} else {
 								this.stats.add("discarded", "frames", 1);
@@ -957,8 +957,8 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 				options.doc = null;
 				options.win = null;
 				options.url = resourceURL;
-				if (!DomUtil.testIgnoredPath(resourceURL) && DomUtil.testValidPath(resourceURL, this.baseURI, this.options.url)) {
-					const processor = new PageProcessor(options);
+				if (!Util.testIgnoredPath(resourceURL) && Util.testValidPath(resourceURL, this.baseURI, this.options.url)) {
+					const processor = new Runner(options);
 					this.relImportProcessors.set(linkElement, processor);
 					await processor.loadPage();
 					return processor.initialize();
@@ -988,7 +988,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 				if (this.options.compressCSS) {
 					styleContent = docUtil.compressCSS(styleContent);
 				}
-				styleContent = DomProcessorHelper.resolveStylesheetURLs(styleContent, this.baseURI, this.options);
+				styleContent = ProcessorHelper.resolveStylesheetURLs(styleContent, this.baseURI, this.options);
 				const declarationList = cssTree.parse(styleContent, { context: "declarationList" });
 				this.styles.set(element, declarationList);
 			});
@@ -996,7 +996,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 
 		async processStyleAttributes() {
 			return Promise.all(Array.from(this.styles).map(([, declarationList]) =>
-				DomProcessorHelper.processStyle(declarationList.children.toArray(), this.baseURI, this.options, this.cssVariables, this.batchRequest)
+				ProcessorHelper.processStyle(declarationList.children.toArray(), this.baseURI, this.options, this.cssVariables, this.batchRequest)
 			));
 		}
 
@@ -1013,9 +1013,9 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		}
 	}
 
-	// ---------
-	// DomHelper
-	// ---------
+	// ---------------
+	// ProcessorHelper
+	// ---------------
 	const REGEXP_AMP = /&/g;
 	const REGEXP_NBSP = /\u00a0/g;
 	const REGEXP_START_TAG = /</g;
@@ -1031,51 +1031,51 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 	const PREFIX_DATA_URI_VND = "data:application/vnd.";
 	const SINGLE_FILE_VARIABLE_NAME_PREFIX = "--sf-img-";
 
-	class DomProcessorHelper {
+	class ProcessorHelper {
 		static async evalTemplate(template, options, content, dontReplaceSlash) {
 			const date = new Date();
 			const url = docUtil.parseURL(options.url);
-			template = await DomUtil.evalTemplateVariable(template, "page-title", () => options.title || "No title", dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "page-language", () => options.info.lang || "No language", dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "page-description", () => options.info.description || "No description", dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "page-author", () => options.info.author || "No author", dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "page-creator", () => options.info.creator || "No creator", dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "page-publisher", () => options.info.publisher || "No publisher", dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "datetime-iso", () => date.toISOString(), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "date-iso", () => date.toISOString().split("T")[0], dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "time-iso", () => date.toISOString().split("T")[1].split("Z")[0], dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "date-locale", () => date.toLocaleDateString(), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "time-locale", () => date.toLocaleTimeString(), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "day-locale", () => String(date.getDate()).padStart(2, "0"), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "month-locale", () => String(date.getMonth() + 1).padStart(2, "0"), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "year-locale", () => String(date.getFullYear()), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "datetime-locale", () => date.toLocaleString(), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "datetime-utc", () => date.toUTCString(), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "day-utc", () => String(date.getUTCDate()).padStart(2, "0"), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "month-utc", () => String(date.getUTCMonth() + 1).padStart(2, "0"), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "year-utc", () => String(date.getUTCFullYear()), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "hours-locale", () => String(date.getHours()).padStart(2, "0"), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "minutes-locale", () => String(date.getMinutes()).padStart(2, "0"), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "seconds-locale", () => String(date.getSeconds()).padStart(2, "0"), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "hours-utc", () => String(date.getUTCHours()).padStart(2, "0"), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "minutes-utc", () => String(date.getUTCMinutes()).padStart(2, "0"), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "seconds-utc", () => String(date.getUTCSeconds()).padStart(2, "0"), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "url-hash", () => url.hash.substring(1), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "url-host", () => url.host.replace(/\/$/, ""), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "url-hostname", () => url.hostname.replace(/\/$/, ""), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "url-href", () => url.href, dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "url-password", () => url.password, dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "url-pathname", () => url.pathname.replace(/^\//, "").replace(/\/$/, ""), dontReplaceSlash === undefined ? true : dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "url-port", () => url.port, dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "url-protocol", () => url.protocol, dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "url-search", () => url.search.substring(1), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "url-username", () => url.username, dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "tab-id", () => String(options.tabId || "No tab id"), dontReplaceSlash);
-			template = await DomUtil.evalTemplateVariable(template, "url-last-segment", () => DomUtil.getLastSegment(url), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "page-title", () => options.title || "No title", dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "page-language", () => options.info.lang || "No language", dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "page-description", () => options.info.description || "No description", dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "page-author", () => options.info.author || "No author", dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "page-creator", () => options.info.creator || "No creator", dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "page-publisher", () => options.info.publisher || "No publisher", dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "datetime-iso", () => date.toISOString(), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "date-iso", () => date.toISOString().split("T")[0], dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "time-iso", () => date.toISOString().split("T")[1].split("Z")[0], dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "date-locale", () => date.toLocaleDateString(), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "time-locale", () => date.toLocaleTimeString(), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "day-locale", () => String(date.getDate()).padStart(2, "0"), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "month-locale", () => String(date.getMonth() + 1).padStart(2, "0"), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "year-locale", () => String(date.getFullYear()), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "datetime-locale", () => date.toLocaleString(), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "datetime-utc", () => date.toUTCString(), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "day-utc", () => String(date.getUTCDate()).padStart(2, "0"), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "month-utc", () => String(date.getUTCMonth() + 1).padStart(2, "0"), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "year-utc", () => String(date.getUTCFullYear()), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "hours-locale", () => String(date.getHours()).padStart(2, "0"), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "minutes-locale", () => String(date.getMinutes()).padStart(2, "0"), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "seconds-locale", () => String(date.getSeconds()).padStart(2, "0"), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "hours-utc", () => String(date.getUTCHours()).padStart(2, "0"), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "minutes-utc", () => String(date.getUTCMinutes()).padStart(2, "0"), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "seconds-utc", () => String(date.getUTCSeconds()).padStart(2, "0"), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "url-hash", () => url.hash.substring(1), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "url-host", () => url.host.replace(/\/$/, ""), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "url-hostname", () => url.hostname.replace(/\/$/, ""), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "url-href", () => url.href, dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "url-password", () => url.password, dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "url-pathname", () => url.pathname.replace(/^\//, "").replace(/\/$/, ""), dontReplaceSlash === undefined ? true : dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "url-port", () => url.port, dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "url-protocol", () => url.protocol, dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "url-search", () => url.search.substring(1), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "url-username", () => url.username, dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "tab-id", () => String(options.tabId || "No tab id"), dontReplaceSlash);
+			template = await Util.evalTemplateVariable(template, "url-last-segment", () => Util.getLastSegment(url), dontReplaceSlash);
 			if (content) {
-				template = await DomUtil.evalTemplateVariable(template, "digest-sha-256", async () => docUtil.digest("SHA-256", content), dontReplaceSlash);
-				template = await DomUtil.evalTemplateVariable(template, "digest-sha-384", async () => docUtil.digest("SHA-384", content), dontReplaceSlash);
-				template = await DomUtil.evalTemplateVariable(template, "digest-sha-512", async () => docUtil.digest("SHA-512", content), dontReplaceSlash);
+				template = await Util.evalTemplateVariable(template, "digest-sha-256", async () => docUtil.digest("SHA-256", content), dontReplaceSlash);
+				template = await Util.evalTemplateVariable(template, "digest-sha-384", async () => docUtil.digest("SHA-384", content), dontReplaceSlash);
+				template = await Util.evalTemplateVariable(template, "digest-sha-512", async () => docUtil.digest("SHA-512", content), dontReplaceSlash);
 			}
 			return template;
 		}
@@ -1092,9 +1092,9 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		}
 
 		static processShortcutIcons(doc) {
-			let shortcutIcon = DomUtil.findShortcutIcon(Array.from(doc.querySelectorAll("link[href][rel=\"icon\"], link[href][rel=\"shortcut icon\"]")));
+			let shortcutIcon = Util.findShortcutIcon(Array.from(doc.querySelectorAll("link[href][rel=\"icon\"], link[href][rel=\"shortcut icon\"]")));
 			if (!shortcutIcon) {
-				shortcutIcon = DomUtil.findShortcutIcon(Array.from(doc.querySelectorAll("link[href][rel*=\"icon\"]")));
+				shortcutIcon = Util.findShortcutIcon(Array.from(doc.querySelectorAll("link[href][rel*=\"icon\"]")));
 				if (shortcutIcon) {
 					shortcutIcon.rel = "icon";
 				}
@@ -1160,30 +1160,30 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		}
 
 		static async resolveImportURLs(stylesheetContent, baseURI, options) {
-			stylesheetContent = DomProcessorHelper.resolveStylesheetURLs(stylesheetContent, baseURI, options);
-			const imports = DomUtil.getImportFunctions(stylesheetContent);
+			stylesheetContent = ProcessorHelper.resolveStylesheetURLs(stylesheetContent, baseURI, options);
+			const imports = Util.getImportFunctions(stylesheetContent);
 			await Promise.all(imports.map(async cssImport => {
-				const match = DomUtil.matchImport(cssImport);
+				const match = Util.matchImport(cssImport);
 				if (match) {
-					let resourceURL = DomUtil.normalizeURL(match.resourceURL);
-					if (!DomUtil.testIgnoredPath(resourceURL) && DomUtil.testValidPath(resourceURL, baseURI, options.url)) {
+					let resourceURL = Util.normalizeURL(match.resourceURL);
+					if (!Util.testIgnoredPath(resourceURL) && Util.testValidPath(resourceURL, baseURI, options.url)) {
 						try {
 							resourceURL = docUtil.resolveURL(match.resourceURL, baseURI);
 						} catch (error) {
 							// ignored
 						}
-						if (DomUtil.testValidURL(resourceURL, baseURI, options.url)) {
+						if (Util.testValidURL(resourceURL, baseURI, options.url)) {
 							const downloadOptions = { asDataURI: false, maxResourceSize: options.maxResourceSize, maxResourceSizeEnabled: options.maxResourceSizeEnabled, validateTextContentType: true };
 							const content = await docUtil.getContent(resourceURL, downloadOptions);
 							resourceURL = content.resourceURL;
-							let importedStylesheetContent = DomUtil.removeCssComments(content.data);
+							let importedStylesheetContent = Util.removeCssComments(content.data);
 							if (options.compressCSS) {
 								importedStylesheetContent = docUtil.compressCSS(importedStylesheetContent);
 							}
-							importedStylesheetContent = DomUtil.wrapMediaQuery(importedStylesheetContent, match.media);
+							importedStylesheetContent = Util.wrapMediaQuery(importedStylesheetContent, match.media);
 							if (stylesheetContent.includes(cssImport)) {
-								importedStylesheetContent = await DomProcessorHelper.resolveImportURLs(importedStylesheetContent, resourceURL, options);
-								stylesheetContent = stylesheetContent.replace(DomUtil.getRegExp(cssImport), importedStylesheetContent);
+								importedStylesheetContent = await ProcessorHelper.resolveImportURLs(importedStylesheetContent, resourceURL, options);
+								stylesheetContent = stylesheetContent.replace(Util.getRegExp(cssImport), importedStylesheetContent);
 							}
 						}
 					}
@@ -1193,20 +1193,20 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		}
 
 		static resolveStylesheetURLs(stylesheetContent, baseURI, options) {
-			const urlFunctions = DomUtil.getUrlFunctions(stylesheetContent);
+			const urlFunctions = Util.getUrlFunctions(stylesheetContent);
 			urlFunctions.map(urlFunction => {
-				const originalResourceURL = DomUtil.matchURL(urlFunction);
-				const resourceURL = DomUtil.normalizeURL(originalResourceURL);
-				if (!DomUtil.testIgnoredPath(resourceURL)) {
-					if (DomUtil.testValidPath(resourceURL, baseURI, options.url)) {
+				const originalResourceURL = Util.matchURL(urlFunction);
+				const resourceURL = Util.normalizeURL(originalResourceURL);
+				if (!Util.testIgnoredPath(resourceURL)) {
+					if (Util.testValidPath(resourceURL, baseURI, options.url)) {
 						let resolvedURL;
 						try {
 							resolvedURL = docUtil.resolveURL(resourceURL, baseURI);
 						} catch (error) {
 							// ignored
 						}
-						if (DomUtil.testValidURL(resolvedURL, baseURI, options.url) && resourceURL != resolvedURL && stylesheetContent.includes(urlFunction)) {
-							stylesheetContent = stylesheetContent.replace(DomUtil.getRegExp(urlFunction), urlFunction.replace(originalResourceURL, resolvedURL));
+						if (Util.testValidURL(resolvedURL, baseURI, options.url) && resourceURL != resolvedURL && stylesheetContent.includes(urlFunction)) {
+							stylesheetContent = stylesheetContent.replace(Util.getRegExp(urlFunction), urlFunction.replace(originalResourceURL, resolvedURL));
 						}
 					} else {
 						let newUrlFunction;
@@ -1215,13 +1215,13 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 						} else {
 							newUrlFunction = "url(" + EMPTY_DATA_URI + ")";
 						}
-						stylesheetContent = stylesheetContent.replace(DomUtil.getRegExp(urlFunction), newUrlFunction);
+						stylesheetContent = stylesheetContent.replace(Util.getRegExp(urlFunction), newUrlFunction);
 					}
 				} else {
 					if (resourceURL.startsWith(DATA_URI_PREFIX)) {
 						const escapedResourceURL = resourceURL.replace(REGEXP_AMP, "&amp;").replace(REGEXP_NBSP, "&nbsp;").replace(REGEXP_START_TAG, "&lt;").replace(REGEXP_END_TAG, "&gt;");
 						if (escapedResourceURL != resourceURL && stylesheetContent.includes(urlFunction)) {
-							stylesheetContent = stylesheetContent.replace(DomUtil.getRegExp(urlFunction), urlFunction.replace(originalResourceURL, escapedResourceURL));
+							stylesheetContent = stylesheetContent.replace(Util.getRegExp(urlFunction), urlFunction.replace(originalResourceURL, escapedResourceURL));
 						}
 					}
 				}
@@ -1230,16 +1230,16 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		}
 
 		static async resolveLinkStylesheetURLs(resourceURL, baseURI, options) {
-			resourceURL = DomUtil.normalizeURL(resourceURL);
+			resourceURL = Util.normalizeURL(resourceURL);
 			if (resourceURL && resourceURL != baseURI && resourceURL != ABOUT_BLANK_URI) {
 				const downloadOptions = { asDataURI: false, maxResourceSize: options.maxResourceSize, maxResourceSizeEnabled: options.maxResourceSizeEnabled, charset: options.charset };
 				const content = await docUtil.getContent(resourceURL, downloadOptions);
 				resourceURL = content.resourceURL;
-				let stylesheetContent = DomUtil.removeCssComments(content.data);
+				let stylesheetContent = Util.removeCssComments(content.data);
 				if (options.compressCSS) {
 					stylesheetContent = docUtil.compressCSS(stylesheetContent);
 				}
-				stylesheetContent = await DomProcessorHelper.resolveImportURLs(stylesheetContent, resourceURL, options);
+				stylesheetContent = await ProcessorHelper.resolveImportURLs(stylesheetContent, resourceURL, options);
 				return stylesheetContent;
 			}
 		}
@@ -1267,12 +1267,12 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			async function processFontFaceRule(cssRule) {
 				await Promise.all(cssRule.block.children.toArray().map(async declaration => {
 					if (declaration.type == "Declaration" && declaration.value.children) {
-						const urlFunctions = DomUtil.getUrlFunctions(DomUtil.getCSSValue(declaration.value));
+						const urlFunctions = Util.getUrlFunctions(Util.getCSSValue(declaration.value));
 						await Promise.all(urlFunctions.map(async urlFunction => {
-							const originalResourceURL = DomUtil.matchURL(urlFunction);
-							const resourceURL = DomUtil.normalizeURL(originalResourceURL);
-							if (!DomUtil.testIgnoredPath(resourceURL)) {
-								if (DomUtil.testValidURL(resourceURL, baseURI, options.url)) {
+							const originalResourceURL = Util.matchURL(urlFunction);
+							const resourceURL = Util.normalizeURL(originalResourceURL);
+							if (!Util.testIgnoredPath(resourceURL)) {
+								if (Util.testValidURL(resourceURL, baseURI, options.url)) {
 									let { content } = await batchRequest.addURL(resourceURL);
 									let validResource = content == EMPTY_DATA_URI || content.startsWith(PREFIX_DATA_URI_VND) || content.startsWith(PREFIX_DATA_URI_IMAGE_SVG);
 									if (!validResource) {
@@ -1282,7 +1282,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 										content = EMPTY_DATA_URI;
 									}
 									declaration.value.children.forEach(token => {
-										if (token.type == "Url" && docUtil.removeQuotes(DomUtil.getCSSValue(token.value)) == originalResourceURL) {
+										if (token.type == "Url" && docUtil.removeQuotes(Util.getCSSValue(token.value)) == originalResourceURL) {
 											token.value.value = content;
 										}
 									});
@@ -1297,12 +1297,12 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		static async processStyle(declarations, baseURI, options, cssVariables, batchRequest) {
 			await Promise.all(declarations.map(async declaration => {
 				if (declaration.type == "Declaration" && declaration.value.children) {
-					const urlFunctions = DomUtil.getUrlFunctions(DomUtil.getCSSValue(declaration.value));
+					const urlFunctions = Util.getUrlFunctions(Util.getCSSValue(declaration.value));
 					await Promise.all(urlFunctions.map(async urlFunction => {
-						const originalResourceURL = DomUtil.matchURL(urlFunction);
-						const resourceURL = DomUtil.normalizeURL(originalResourceURL);
-						if (!DomUtil.testIgnoredPath(resourceURL)) {
-							if (DomUtil.testValidURL(resourceURL, baseURI, options.url)) {
+						const originalResourceURL = Util.matchURL(urlFunction);
+						const resourceURL = Util.normalizeURL(originalResourceURL);
+						if (!Util.testIgnoredPath(resourceURL)) {
+							if (Util.testValidURL(resourceURL, baseURI, options.url)) {
 								let { content, indexResource, duplicate } = await batchRequest.addURL(resourceURL);
 								if (duplicate && options.groupDuplicateImages) {
 									const tokens = [];
@@ -1326,7 +1326,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 					if (token.data.children) {
 						findURLToken(url, token.data.children, callback);
 					}
-					if (token.data.type == "Url" && docUtil.removeQuotes(DomUtil.getCSSValue(token.data.value)) == url) {
+					if (token.data.type == "Url" && docUtil.removeQuotes(Util.getCSSValue(token.data.value)) == url) {
 						callback(token, children);
 					}
 				}
@@ -1336,16 +1336,16 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		static async processAttribute(doc, resourceElements, attributeName, prefixDataURI, baseURI, options, cssVariables, styles, batchRequest, processDuplicates, removeElementIfMissing) {
 			await Promise.all(Array.from(resourceElements).map(async resourceElement => {
 				let resourceURL = resourceElement.getAttribute(attributeName);
-				resourceURL = DomUtil.normalizeURL(resourceURL);
-				if (!DomUtil.testIgnoredPath(resourceURL)) {
+				resourceURL = Util.normalizeURL(resourceURL);
+				if (!Util.testIgnoredPath(resourceURL)) {
 					resourceElement.setAttribute(attributeName, EMPTY_IMAGE);
-					if (DomUtil.testValidPath(resourceURL, baseURI, options.url)) {
+					if (Util.testValidPath(resourceURL, baseURI, options.url)) {
 						try {
 							resourceURL = docUtil.resolveURL(resourceURL, baseURI);
 						} catch (error) {
 							// ignored
 						}
-						if (DomUtil.testValidURL(resourceURL, baseURI, options.url)) {
+						if (Util.testValidURL(resourceURL, baseURI, options.url)) {
 							const { content, indexResource, duplicate } = await batchRequest.addURL(resourceURL);
 							if (removeElementIfMissing && content == EMPTY_DATA_URI) {
 								resourceElement.remove();
@@ -1353,7 +1353,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 								if (content.startsWith(prefixDataURI) || content.startsWith(PREFIX_DATA_URI_NO_MIMETYPE) || content.match(PREFIX_DATA_URI_OCTET_STREAM) || content.match(PREFIX_DATA_URI_NULL_STREAM)) {
 									const isSVG = content.startsWith(PREFIX_DATA_URI_IMAGE_SVG);
 									if (processDuplicates && duplicate && options.groupDuplicateImages && !isSVG) {
-										if (DomUtil.replaceImageSource(resourceElement, SINGLE_FILE_VARIABLE_NAME_PREFIX + indexResource, options)) {
+										if (Util.replaceImageSource(resourceElement, SINGLE_FILE_VARIABLE_NAME_PREFIX + indexResource, options)) {
 											cssVariables.set(indexResource, content);
 											const declarationList = cssTree.parse(resourceElement.getAttribute("style"), { context: "declarationList" });
 											styles.set(resourceElement, declarationList);
@@ -1375,15 +1375,15 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			const attributeName = "xlink:href";
 			await Promise.all(Array.from(resourceElements).map(async resourceElement => {
 				const originalResourceURL = resourceElement.getAttribute(attributeName);
-				let resourceURL = DomUtil.normalizeURL(originalResourceURL);
-				if (DomUtil.testValidPath(resourceURL, baseURI, options.url) && !DomUtil.testIgnoredPath(resourceURL)) {
+				let resourceURL = Util.normalizeURL(originalResourceURL);
+				if (Util.testValidPath(resourceURL, baseURI, options.url) && !Util.testIgnoredPath(resourceURL)) {
 					resourceElement.setAttribute(attributeName, EMPTY_IMAGE);
 					try {
 						resourceURL = docUtil.resolveURL(resourceURL, baseURI);
 					} catch (error) {
 						// ignored
 					}
-					if (DomUtil.testValidURL(resourceURL, baseURI, options.url)) {
+					if (Util.testValidURL(resourceURL, baseURI, options.url)) {
 						try {
 							const { content } = await batchRequest.addURL(resourceURL, false);
 							const DOMParser = docUtil.getParser();
@@ -1416,15 +1416,15 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			await Promise.all(Array.from(resourceElements).map(async resourceElement => {
 				const srcset = docUtil.parseSrcset(resourceElement.getAttribute(attributeName));
 				const srcsetValues = await Promise.all(srcset.map(async srcsetValue => {
-					let resourceURL = DomUtil.normalizeURL(srcsetValue.url);
-					if (!DomUtil.testIgnoredPath(resourceURL)) {
-						if (DomUtil.testValidPath(resourceURL, baseURI, options.url)) {
+					let resourceURL = Util.normalizeURL(srcsetValue.url);
+					if (!Util.testIgnoredPath(resourceURL)) {
+						if (Util.testValidPath(resourceURL, baseURI, options.url)) {
 							try {
 								resourceURL = docUtil.resolveURL(resourceURL, baseURI);
 							} catch (error) {
 								// ignored
 							}
-							if (DomUtil.testValidURL(resourceURL, baseURI, options.url)) {
+							if (Util.testValidURL(resourceURL, baseURI, options.url)) {
 								const { content } = await batchRequest.addURL(resourceURL);
 								if (!content.startsWith(prefixDataURI) && !content.startsWith(PREFIX_DATA_URI_NO_MIMETYPE) && !content.match(PREFIX_DATA_URI_OCTET_STREAM) && !content.match(PREFIX_DATA_URI_NULL_STREAM)) {
 									resourceElement.setAttribute(attributeName, EMPTY_IMAGE);
@@ -1446,9 +1446,9 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 
 	}
 
-	// -------
-	// DomUtil
-	// -------
+	// ----
+	// Util
+	// ----
 	const DATA_URI_PREFIX = "data:";
 	const BLOB_URI_PREFIX = "blob:";
 	const HTTP_URI_PREFIX = /^https?:\/\//;
@@ -1469,7 +1469,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 	const REGEXP_IMPORT_NO_QUOTES_FN = /@import\s*(.*?)\s*(.*?)(;|$|})/i;
 	const REGEXP_ESCAPE = /([{}()^$&.*?/+|[\\\\]|\]|-)/g;
 
-	class DomUtil {
+	class Util {
 		static normalizeURL(url) {
 			if (!url || url.startsWith(DATA_URI_PREFIX)) {
 				return url;
@@ -1551,7 +1551,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		}
 
 		static testValidURL(resourceURL, baseURI, docURL) {
-			return DomUtil.testValidPath(resourceURL, baseURI, docURL) && (resourceURL.match(HTTP_URI_PREFIX) || resourceURL.match(FILE_URI_PREFIX) || resourceURL.startsWith(BLOB_URI_PREFIX)) && resourceURL.match(NOT_EMPTY_URL);
+			return Util.testValidPath(resourceURL, baseURI, docURL) && (resourceURL.match(HTTP_URI_PREFIX) || resourceURL.match(FILE_URI_PREFIX) || resourceURL.startsWith(BLOB_URI_PREFIX)) && resourceURL.match(NOT_EMPTY_URL);
 		}
 
 		static matchImport(stylesheetContent) {
@@ -1604,7 +1604,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 					if (imgData.backgroundColor) {
 						backgroundStyle["background-color"] = imgData.backgroundColor;
 					}
-					DomProcessorHelper.setBackgroundImage(imgElement, "var(" + variableName + ")", backgroundStyle);
+					ProcessorHelper.setBackgroundImage(imgElement, "var(" + variableName + ")", backgroundStyle);
 					imgElement.removeAttribute(dataAttributeName);
 					return true;
 				}