single-file-core 1.5.57 → 1.5.58
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/helper.js +105 -8
- package/core/index.js +6 -0
- package/core/lib/processor-helper-common.js +8 -28
- package/core/lib/processor-helper-inline.js +5 -0
- package/core/lib/processor-helper.js +4 -1
- package/core/util.js +6 -15
- package/package.json +1 -1
package/core/helper.js
CHANGED
|
@@ -77,6 +77,7 @@ const EMPTY_RESOURCE = "data:,";
|
|
|
77
77
|
const DEFAULT_REPLACED_CHARACTERS = ["~", "+", "?", "%", "*", ":", "|", "\"", "<", ">", "\\\\", "\x00-\x1f", "\x7F"];
|
|
78
78
|
const DEFAULT_REPLACEMENT_CHARACTER = "_";
|
|
79
79
|
const DEFAULT_REPLACEMENT_CHARACTERS = ["~", "+", "?", "%", "*", ":", "|", """, "<", ">", "\"];
|
|
80
|
+
const NESTING_TRACK_ID_ATTRIBUTE_NAME = "data-sf-nesting-track-id";
|
|
80
81
|
const addEventListener = (type, listener, options) => globalThis.addEventListener(type, listener, options);
|
|
81
82
|
// eslint-disable-next-line no-unused-vars
|
|
82
83
|
const dispatchEvent = event => { try { globalThis.dispatchEvent(event); } catch (error) { /* ignored */ } };
|
|
@@ -87,6 +88,7 @@ const Blob = globalThis.Blob;
|
|
|
87
88
|
const CustomEvent = globalThis.CustomEvent;
|
|
88
89
|
const MutationObserver = globalThis.MutationObserver;
|
|
89
90
|
const URL = globalThis.URL;
|
|
91
|
+
const DOMParser = globalThis.DOMParser;
|
|
90
92
|
|
|
91
93
|
export {
|
|
92
94
|
initUserScriptHandler,
|
|
@@ -103,6 +105,8 @@ export {
|
|
|
103
105
|
getContentSize,
|
|
104
106
|
digest,
|
|
105
107
|
getValidFilename,
|
|
108
|
+
parseDocContent,
|
|
109
|
+
fixInvalidNesting,
|
|
106
110
|
ON_BEFORE_CAPTURE_EVENT_NAME,
|
|
107
111
|
ON_AFTER_CAPTURE_EVENT_NAME,
|
|
108
112
|
WIN_ID_ATTRIBUTE_NAME,
|
|
@@ -130,7 +134,8 @@ export {
|
|
|
130
134
|
INFOBAR_TAGNAME,
|
|
131
135
|
WAIT_FOR_USERSCRIPT_PROPERTY_NAME,
|
|
132
136
|
MESSAGE_PREFIX,
|
|
133
|
-
NO_SCRIPT_PROPERTY_NAME
|
|
137
|
+
NO_SCRIPT_PROPERTY_NAME,
|
|
138
|
+
NESTING_TRACK_ID_ATTRIBUTE_NAME
|
|
134
139
|
};
|
|
135
140
|
|
|
136
141
|
function initUserScriptHandler() {
|
|
@@ -205,13 +210,7 @@ function preProcessDoc(doc, win, options) {
|
|
|
205
210
|
const invalidElements = new Map();
|
|
206
211
|
let elementsInfo;
|
|
207
212
|
if (win && doc.documentElement) {
|
|
208
|
-
doc
|
|
209
|
-
const placeHolderElement = doc.createElement("template");
|
|
210
|
-
placeHolderElement.setAttribute(INVALID_ELEMENT_ATTRIBUTE_NAME, "");
|
|
211
|
-
placeHolderElement.content.appendChild(element.cloneNode(true));
|
|
212
|
-
invalidElements.set(element, placeHolderElement);
|
|
213
|
-
element.replaceWith(placeHolderElement);
|
|
214
|
-
});
|
|
213
|
+
markInvalidNesting(doc);
|
|
215
214
|
elementsInfo = getElementsInfo(win, doc, doc.documentElement, options);
|
|
216
215
|
if (options.moveStylesInHead) {
|
|
217
216
|
doc.querySelectorAll("body style, body ~ style").forEach(element => {
|
|
@@ -260,6 +259,87 @@ function preProcessDoc(doc, win, options) {
|
|
|
260
259
|
};
|
|
261
260
|
}
|
|
262
261
|
|
|
262
|
+
function markInvalidNesting(doc) {
|
|
263
|
+
addTrackIds(doc.body);
|
|
264
|
+
const verificationDoc = parseDocContent(serialize(doc));
|
|
265
|
+
const markedMap = buildTrackIdMap(doc.body);
|
|
266
|
+
const normalizedMap = buildTrackIdMap(verificationDoc.body);
|
|
267
|
+
const trackIds = new Set();
|
|
268
|
+
Object.keys(markedMap).forEach(id => {
|
|
269
|
+
if (id in normalizedMap) {
|
|
270
|
+
const markedParent = markedMap[id].parentElement?.getAttribute(NESTING_TRACK_ID_ATTRIBUTE_NAME) || null;
|
|
271
|
+
const normalizedParent = normalizedMap[id]?.parentElement?.getAttribute(NESTING_TRACK_ID_ATTRIBUTE_NAME) || null;
|
|
272
|
+
if (markedParent !== normalizedParent) {
|
|
273
|
+
let current = markedMap[id];
|
|
274
|
+
while (current && current !== doc.body) {
|
|
275
|
+
const currentId = current.getAttribute(NESTING_TRACK_ID_ATTRIBUTE_NAME);
|
|
276
|
+
if (currentId) {
|
|
277
|
+
trackIds.add(currentId);
|
|
278
|
+
}
|
|
279
|
+
current = current.parentElement;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
cleanupTrackIds(doc.body, trackIds);
|
|
285
|
+
|
|
286
|
+
function addTrackIds(element, index = 0, parentTrackId = "") {
|
|
287
|
+
const trackId = parentTrackId ? `${parentTrackId}.${index + 1}` : `${index + 1}`;
|
|
288
|
+
element.setAttribute(NESTING_TRACK_ID_ATTRIBUTE_NAME, trackId);
|
|
289
|
+
Array.from(element.children).forEach((child, indexChild) => addTrackIds(child, indexChild, trackId));
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function buildTrackIdMap(element) {
|
|
293
|
+
const trackIds = {};
|
|
294
|
+
traverse(element);
|
|
295
|
+
return trackIds;
|
|
296
|
+
|
|
297
|
+
function traverse(element) {
|
|
298
|
+
if (element.getAttribute) {
|
|
299
|
+
const id = element.getAttribute(NESTING_TRACK_ID_ATTRIBUTE_NAME);
|
|
300
|
+
if (id) {
|
|
301
|
+
trackIds[id] = element;
|
|
302
|
+
}
|
|
303
|
+
Array.from(element.children).forEach(traverse);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function cleanupTrackIds(element, toKeep) {
|
|
309
|
+
const id = element.getAttribute(NESTING_TRACK_ID_ATTRIBUTE_NAME);
|
|
310
|
+
if (id && !toKeep.has(id)) {
|
|
311
|
+
element.removeAttribute(NESTING_TRACK_ID_ATTRIBUTE_NAME);
|
|
312
|
+
}
|
|
313
|
+
Array.from(element.children).forEach(child => cleanupTrackIds(child, toKeep));
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function fixInvalidNesting(document, NESTING_TRACK_ID_ATTRIBUTE_NAME) {
|
|
318
|
+
const trackIds = {};
|
|
319
|
+
document.currentScript.remove();
|
|
320
|
+
buildTrackIdMap(document.body);
|
|
321
|
+
Object.keys(trackIds).forEach(id => {
|
|
322
|
+
const element = trackIds[id];
|
|
323
|
+
const idParts = id.split(".");
|
|
324
|
+
if (idParts.length > 1) {
|
|
325
|
+
const parentId = idParts.slice(0, -1).join(".");
|
|
326
|
+
const expectedParent = trackIds[parentId];
|
|
327
|
+
if (expectedParent && element.parentElement !== expectedParent) {
|
|
328
|
+
expectedParent.appendChild(element);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
Object.keys(trackIds).forEach(id => trackIds[id].removeAttribute(NESTING_TRACK_ID_ATTRIBUTE_NAME));
|
|
333
|
+
|
|
334
|
+
function buildTrackIdMap(element) {
|
|
335
|
+
const id = element.getAttribute(NESTING_TRACK_ID_ATTRIBUTE_NAME);
|
|
336
|
+
if (id) {
|
|
337
|
+
trackIds[id] = element;
|
|
338
|
+
}
|
|
339
|
+
Array.from(element.children).forEach(buildTrackIdMap);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
263
343
|
function getElementsInfo(win, doc, element, options, data = { usedFonts: new Map(), canvases: [], images: [], posters: [], videos: [], shadowRoots: [], markedElements: [] }, adoptedStyleSheetsCache = new Map(), ascendantHidden) {
|
|
264
344
|
if (element.childNodes) {
|
|
265
345
|
const elements = Array.from(element.childNodes).filter(node => (node instanceof win.HTMLElement) || (node instanceof win.SVGElement) || (node instanceof globalThis.HTMLElement) || (node instanceof globalThis.SVGElement));
|
|
@@ -746,4 +826,21 @@ function getValidFilename(filename, replacedCharacters = DEFAULT_REPLACED_CHARAC
|
|
|
746
826
|
.replace(/\.\//g, "." + replacementCharacter)
|
|
747
827
|
.replace(/\/\./g, "/" + replacementCharacter);
|
|
748
828
|
return filename;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
function parseDocContent(content, baseURI) {
|
|
832
|
+
const doc = (new DOMParser()).parseFromString(content, "text/html");
|
|
833
|
+
if (!doc.head) {
|
|
834
|
+
doc.documentElement.insertBefore(doc.createElement("HEAD"), doc.body);
|
|
835
|
+
}
|
|
836
|
+
let baseElement = doc.querySelector("base");
|
|
837
|
+
if (!baseElement || !baseElement.getAttribute("href")) {
|
|
838
|
+
if (baseElement) {
|
|
839
|
+
baseElement.remove();
|
|
840
|
+
}
|
|
841
|
+
baseElement = doc.createElement("base");
|
|
842
|
+
baseElement.setAttribute("href", baseURI);
|
|
843
|
+
doc.head.insertBefore(baseElement, doc.head.firstChild);
|
|
844
|
+
}
|
|
845
|
+
return doc;
|
|
749
846
|
}
|
package/core/index.js
CHANGED
|
@@ -582,6 +582,11 @@ class Processor {
|
|
|
582
582
|
if (this.options.displayStats) {
|
|
583
583
|
size = util.getContentSize(this.doc.documentElement.outerHTML);
|
|
584
584
|
}
|
|
585
|
+
if (this.doc.querySelector(`[${util.NESTING_TRACK_ID_ATTRIBUTE_NAME}]`)) {
|
|
586
|
+
const scriptElement = this.doc.createElement("script");
|
|
587
|
+
scriptElement.textContent = `(${util.getFixInvalidNestingSource()})(document, "${util.NESTING_TRACK_ID_ATTRIBUTE_NAME}");`;
|
|
588
|
+
this.doc.body.appendChild(scriptElement);
|
|
589
|
+
}
|
|
585
590
|
const content = util.serialize(this.doc, this.options.compressHTML);
|
|
586
591
|
if (this.options.displayStats) {
|
|
587
592
|
const contentSize = util.getContentSize(content);
|
|
@@ -896,6 +901,7 @@ class Processor {
|
|
|
896
901
|
this.doc.querySelectorAll("a[ping], area[ping]").forEach(element => element.removeAttribute("ping"));
|
|
897
902
|
this.doc.querySelectorAll("a[attributionsrc], img[attributionsrc], script[attributionsrc]").forEach(element => element.removeAttribute("attributionsrc"));
|
|
898
903
|
this.doc.querySelectorAll("link[rel=import][href]").forEach(element => element.remove());
|
|
904
|
+
this.doc.querySelectorAll("link[rel=compression-dictionary]").forEach(element => element.remove());
|
|
899
905
|
}
|
|
900
906
|
|
|
901
907
|
replaceInvalidElements() {
|
|
@@ -329,37 +329,17 @@ class ProcessorHelperCommon {
|
|
|
329
329
|
}
|
|
330
330
|
|
|
331
331
|
replacePseudoClassDefined(stylesheet) {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
332
|
+
cssTree.walk(stylesheet, {
|
|
333
|
+
enter: function(node, item, list) {
|
|
334
|
+
if (node.type == "PseudoClassSelector" && node.name == "defined") {
|
|
335
|
+
if (item.prev == null || item.prev.data.type == "Combinator" || item.prev.data.type == "WhiteSpace") {
|
|
336
|
+
list.replace(item, cssTree.parse("*", { context: "selector" }).children.head);
|
|
337
|
+
} else {
|
|
338
|
+
list.remove(item);
|
|
339
339
|
}
|
|
340
340
|
}
|
|
341
341
|
}
|
|
342
|
-
}
|
|
343
|
-
if (removedSelectors.length) {
|
|
344
|
-
removedSelectors.forEach(({ parentSelector, selector }) => {
|
|
345
|
-
if (parentSelector.data.children.size == 0 || !selector.prev || selector.prev.data.type == "Combinator" || selector.prev.data.type == "WhiteSpace") {
|
|
346
|
-
parentSelector.data.children.replace(selector, cssTree.parse("*", { context: "selector" }).children.head);
|
|
347
|
-
} else {
|
|
348
|
-
parentSelector.data.children.remove(selector);
|
|
349
|
-
}
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
function replacePseudoDefinedSelector(selector, parentSelector) {
|
|
354
|
-
if (selector.data.children) {
|
|
355
|
-
for (let childSelector = selector.data.children.head; childSelector; childSelector = childSelector.next) {
|
|
356
|
-
replacePseudoDefinedSelector(childSelector, selector);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
if (selector.data.type == "PseudoClassSelector" && selector.data.name == "defined") {
|
|
360
|
-
removedSelectors.push({ parentSelector, selector });
|
|
361
|
-
}
|
|
362
|
-
}
|
|
342
|
+
});
|
|
363
343
|
}
|
|
364
344
|
|
|
365
345
|
resolveStylesheetURLs(stylesheet, baseURI, workStylesheet) {
|
|
@@ -99,6 +99,11 @@ function getProcessorHelperClass(utilInstance) {
|
|
|
99
99
|
this.removeSingleLineCssComments(stylesheet);
|
|
100
100
|
}
|
|
101
101
|
this.replacePseudoClassDefined(stylesheet);
|
|
102
|
+
options.inlineStylesheets.forEach((content, index) => {
|
|
103
|
+
if (content === element.textContent) {
|
|
104
|
+
options.inlineStylesheets.set(index, this.generateStylesheetContent(stylesheet, options));
|
|
105
|
+
}
|
|
106
|
+
});
|
|
102
107
|
stylesheetInfo.stylesheet = stylesheet;
|
|
103
108
|
} else {
|
|
104
109
|
stylesheets.delete(element);
|
|
@@ -102,7 +102,10 @@ function getProcessorHelperClass(utilInstance) {
|
|
|
102
102
|
linkElement.setAttribute("type", "text/css");
|
|
103
103
|
const name = "stylesheet_" + resources.stylesheets.size + ".css";
|
|
104
104
|
linkElement.setAttribute("href", name);
|
|
105
|
-
|
|
105
|
+
let content = options.inlineStylesheets.get(stylesheetRefIndex);
|
|
106
|
+
const stylesheet = cssTree.parse(content, { context: "stylesheet", parseCustomProperty: true });
|
|
107
|
+
this.replacePseudoClassDefined(stylesheet);
|
|
108
|
+
content = this.generateStylesheetContent(stylesheet, options);
|
|
106
109
|
resources.stylesheets.set(resources.stylesheets.size, { name, content });
|
|
107
110
|
linkElements.set(stylesheetRefIndex, linkElement);
|
|
108
111
|
});
|
package/core/util.js
CHANGED
|
@@ -116,20 +116,7 @@ function getInstance(utilOptions) {
|
|
|
116
116
|
return helper.getValidFilename(filename, replacedCharacters, replacementCharacter, replacementCharacters);
|
|
117
117
|
},
|
|
118
118
|
parseDocContent(content, baseURI) {
|
|
119
|
-
|
|
120
|
-
if (!doc.head) {
|
|
121
|
-
doc.documentElement.insertBefore(doc.createElement("HEAD"), doc.body);
|
|
122
|
-
}
|
|
123
|
-
let baseElement = doc.querySelector("base");
|
|
124
|
-
if (!baseElement || !baseElement.getAttribute("href")) {
|
|
125
|
-
if (baseElement) {
|
|
126
|
-
baseElement.remove();
|
|
127
|
-
}
|
|
128
|
-
baseElement = doc.createElement("base");
|
|
129
|
-
baseElement.setAttribute("href", baseURI);
|
|
130
|
-
doc.head.insertBefore(baseElement, doc.head.firstChild);
|
|
131
|
-
}
|
|
132
|
-
return doc;
|
|
119
|
+
return helper.parseDocContent(content, baseURI);
|
|
133
120
|
},
|
|
134
121
|
parseXMLContent(content) {
|
|
135
122
|
return (new DOMParser()).parseFromString(content, "text/xml");
|
|
@@ -142,6 +129,9 @@ function getInstance(utilOptions) {
|
|
|
142
129
|
return doc;
|
|
143
130
|
}
|
|
144
131
|
},
|
|
132
|
+
getFixInvalidNestingSource() {
|
|
133
|
+
return helper.fixInvalidNesting.toString().replace(/\s+/g, " ");
|
|
134
|
+
},
|
|
145
135
|
async digest(algo, text) {
|
|
146
136
|
return helper.digest(algo, text);
|
|
147
137
|
},
|
|
@@ -229,7 +219,8 @@ function getInstance(utilOptions) {
|
|
|
229
219
|
EMPTY_RESOURCE: helper.EMPTY_RESOURCE,
|
|
230
220
|
INFOBAR_TAGNAME: helper.INFOBAR_TAGNAME,
|
|
231
221
|
WAIT_FOR_USERSCRIPT_PROPERTY_NAME: helper.WAIT_FOR_USERSCRIPT_PROPERTY_NAME,
|
|
232
|
-
NO_SCRIPT_PROPERTY_NAME: helper.NO_SCRIPT_PROPERTY_NAME
|
|
222
|
+
NO_SCRIPT_PROPERTY_NAME: helper.NO_SCRIPT_PROPERTY_NAME,
|
|
223
|
+
NESTING_TRACK_ID_ATTRIBUTE_NAME: helper.NESTING_TRACK_ID_ATTRIBUTE_NAME
|
|
233
224
|
};
|
|
234
225
|
|
|
235
226
|
async function getContent(resourceURL, options) {
|