single-file-core 1.6.12 → 1.6.13
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 +1 -1
- package/core/index.js +45 -44
- package/core/util.js +2 -2
- package/modules/html-serializer.js +8 -8
- package/package.json +1 -1
package/core/helper.js
CHANGED
|
@@ -601,7 +601,7 @@ function fixInvalidNesting(document, NESTING_TRACK_ID_ATTRIBUTE_NAME, preventCle
|
|
|
601
601
|
const id = element.getAttribute(NESTING_TRACK_ID_ATTRIBUTE_NAME);
|
|
602
602
|
const originalElement = trackIds[id];
|
|
603
603
|
if (originalElement != element) {
|
|
604
|
-
if (!preventCleanup) {
|
|
604
|
+
if (!preventCleanup || options.mergeCopies) {
|
|
605
605
|
if (originalElement.contains(element)) {
|
|
606
606
|
element.replaceWith(...element.childNodes);
|
|
607
607
|
} else {
|
package/core/index.js
CHANGED
|
@@ -503,8 +503,7 @@ class Processor {
|
|
|
503
503
|
this.doc = util.parseDocContent(pageContent, this.baseURI);
|
|
504
504
|
util.fixInvalidNesting(this.doc, true, { recreateOnly: true });
|
|
505
505
|
removeInsertedParagraphs(this.doc);
|
|
506
|
-
|
|
507
|
-
util.fixInvalidNesting(this.doc);
|
|
506
|
+
util.fixInvalidNesting(this.doc, true, { mergeCopies: true });
|
|
508
507
|
if (this.options.saveRawPage) {
|
|
509
508
|
let charset;
|
|
510
509
|
this.doc.querySelectorAll("meta[charset]").forEach(element => {
|
|
@@ -612,14 +611,20 @@ class Processor {
|
|
|
612
611
|
if (this.options.displayStats) {
|
|
613
612
|
size = util.getContentSize(this.doc.documentElement.outerHTML);
|
|
614
613
|
}
|
|
615
|
-
restoreNestingPositions(this.nestingPositions);
|
|
616
614
|
const collapsedElementCount = collapseRecreatedElements(this.doc);
|
|
617
|
-
|
|
615
|
+
const invalidNesting = collapsedElementCount || this.doc.querySelector(`[${util.NESTING_TRACK_ID_ATTRIBUTE_NAME}]`);
|
|
616
|
+
if (invalidNesting) {
|
|
618
617
|
const scriptElement = this.doc.createElement("script");
|
|
619
618
|
scriptElement.textContent = `(${util.getFixInvalidNestingSource()})(document, "${util.NESTING_TRACK_ID_ATTRIBUTE_NAME}");`;
|
|
620
619
|
this.doc.body.appendChild(scriptElement);
|
|
621
620
|
}
|
|
622
|
-
|
|
621
|
+
let content = util.serialize(this.doc, this.options.compressHTML);
|
|
622
|
+
if (invalidNesting) {
|
|
623
|
+
const closedParagraphs = getClosedParagraphs(this.doc, content);
|
|
624
|
+
if (closedParagraphs.size) {
|
|
625
|
+
content = util.serialize(this.doc, this.options.compressHTML, closedParagraphs);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
623
628
|
if (this.options.displayStats) {
|
|
624
629
|
const contentSize = util.getContentSize(content);
|
|
625
630
|
this.stats.set("processed", "HTML bytes", contentSize);
|
|
@@ -1010,11 +1015,17 @@ class Processor {
|
|
|
1010
1015
|
}
|
|
1011
1016
|
|
|
1012
1017
|
resetReferrerMeta() {
|
|
1013
|
-
this.doc.querySelectorAll("meta[name=referrer]").forEach(element => element.remove());
|
|
1014
1018
|
const metaElement = this.doc.createElement("meta");
|
|
1015
1019
|
metaElement.setAttribute("name", "referrer");
|
|
1016
1020
|
metaElement.setAttribute("content", "no-referrer");
|
|
1017
|
-
this.doc.
|
|
1021
|
+
const referrerElements = Array.from(this.doc.querySelectorAll("meta[name=referrer]"));
|
|
1022
|
+
const headReferrerElement = referrerElements.find(element => element.parentElement == this.doc.head);
|
|
1023
|
+
if (headReferrerElement) {
|
|
1024
|
+
headReferrerElement.replaceWith(metaElement);
|
|
1025
|
+
} else {
|
|
1026
|
+
this.doc.head.appendChild(metaElement);
|
|
1027
|
+
}
|
|
1028
|
+
referrerElements.forEach(element => element.remove());
|
|
1018
1029
|
}
|
|
1019
1030
|
|
|
1020
1031
|
setInputValues() {
|
|
@@ -1447,7 +1458,6 @@ class Processor {
|
|
|
1447
1458
|
insertShadowRootContents() {
|
|
1448
1459
|
const doc = this.doc;
|
|
1449
1460
|
const options = this.options;
|
|
1450
|
-
const nestingPositions = this.nestingPositions || [];
|
|
1451
1461
|
if (options.shadowRoots && options.shadowRoots.length) {
|
|
1452
1462
|
processElement(this.doc);
|
|
1453
1463
|
}
|
|
@@ -1490,8 +1500,7 @@ class Processor {
|
|
|
1490
1500
|
}
|
|
1491
1501
|
util.fixInvalidNesting(doc, true, { rootElement: templateElement, recreateOnly: true });
|
|
1492
1502
|
removeInsertedParagraphs(templateElement);
|
|
1493
|
-
|
|
1494
|
-
util.fixInvalidNesting(doc, true, { rootElement: templateElement });
|
|
1503
|
+
util.fixInvalidNesting(doc, true, { rootElement: templateElement, mergeCopies: true });
|
|
1495
1504
|
if (templateElement.querySelector(`[${util.NESTING_TRACK_ID_ATTRIBUTE_NAME}]`)) {
|
|
1496
1505
|
templateElement.setAttribute(SHADOWROOT_ATTRIBUTE_NAME, "open");
|
|
1497
1506
|
}
|
|
@@ -1808,33 +1817,6 @@ function testIgnoredPath(resourceURL) {
|
|
|
1808
1817
|
return resourceURL && (resourceURL.startsWith(DATA_URI_PREFIX) || resourceURL == ABOUT_BLANK_URI);
|
|
1809
1818
|
}
|
|
1810
1819
|
|
|
1811
|
-
function getNestingPositions(doc) {
|
|
1812
|
-
return Array.from(doc.querySelectorAll(`[${util.NESTING_TRACK_ID_ATTRIBUTE_NAME}]`)).map(element => ({
|
|
1813
|
-
element,
|
|
1814
|
-
parentNode: element.parentNode,
|
|
1815
|
-
previousSibling: element.previousSibling,
|
|
1816
|
-
nextSibling: element.nextSibling
|
|
1817
|
-
}));
|
|
1818
|
-
}
|
|
1819
|
-
|
|
1820
|
-
function restoreNestingPositions(positions) {
|
|
1821
|
-
if (positions) {
|
|
1822
|
-
positions.forEach(({ element, parentNode, previousSibling, nextSibling }) => {
|
|
1823
|
-
if (element.isConnected && parentNode && parentNode.isConnected) {
|
|
1824
|
-
if (previousSibling && previousSibling.parentNode == parentNode) {
|
|
1825
|
-
parentNode.insertBefore(element, previousSibling.nextSibling);
|
|
1826
|
-
} else if (!previousSibling) {
|
|
1827
|
-
parentNode.insertBefore(element, parentNode.firstChild);
|
|
1828
|
-
} else if (nextSibling && nextSibling.parentNode == parentNode) {
|
|
1829
|
-
parentNode.insertBefore(element, nextSibling);
|
|
1830
|
-
} else {
|
|
1831
|
-
parentNode.appendChild(element);
|
|
1832
|
-
}
|
|
1833
|
-
}
|
|
1834
|
-
});
|
|
1835
|
-
}
|
|
1836
|
-
}
|
|
1837
|
-
|
|
1838
1820
|
function collapseRecreatedElements(doc) {
|
|
1839
1821
|
const elements = Array.from(doc.querySelectorAll(`[${util.NESTING_RECREATED_ATTRIBUTE_NAME}]`)).reverse();
|
|
1840
1822
|
elements.forEach(element => {
|
|
@@ -1850,6 +1832,25 @@ function collapseRecreatedElements(doc) {
|
|
|
1850
1832
|
}
|
|
1851
1833
|
|
|
1852
1834
|
function removeInsertedParagraphs(doc) {
|
|
1835
|
+
getInsertedParagraphs(doc).forEach((_, paragraph) => paragraph.remove());
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
function getClosedParagraphs(doc, content) {
|
|
1839
|
+
const parsedDoc = util.parseDocContent(content);
|
|
1840
|
+
const roots = [];
|
|
1841
|
+
addRoots(parsedDoc);
|
|
1842
|
+
const trackIds = new Set();
|
|
1843
|
+
roots.forEach(root => getInsertedParagraphs(root).forEach(trackId => trackIds.add(trackId)));
|
|
1844
|
+
return new Set(Array.from(doc.querySelectorAll(`[${util.NESTING_TRACK_ID_ATTRIBUTE_NAME}]`)).filter(element =>
|
|
1845
|
+
element.tagName == PARAGRAPH_TAG_NAME && trackIds.has(element.getAttribute(util.NESTING_TRACK_ID_ATTRIBUTE_NAME))));
|
|
1846
|
+
|
|
1847
|
+
function addRoots(root) {
|
|
1848
|
+
roots.push(root);
|
|
1849
|
+
root.querySelectorAll("template").forEach(templateElement => addRoots(templateElement.content));
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
function getInsertedParagraphs(doc) {
|
|
1853
1854
|
const trackedElements = new Map();
|
|
1854
1855
|
doc.querySelectorAll(`[${util.NESTING_TRACK_ID_ATTRIBUTE_NAME}]`).forEach(element =>
|
|
1855
1856
|
trackedElements.set(element.getAttribute(util.NESTING_TRACK_ID_ATTRIBUTE_NAME), element));
|
|
@@ -1858,33 +1859,33 @@ function removeInsertedParagraphs(doc) {
|
|
|
1858
1859
|
const parentTrackId = getParentTrackId(trackId);
|
|
1859
1860
|
const expectedParent = trackedElements.get(parentTrackId);
|
|
1860
1861
|
if (expectedParent && element.parentElement != expectedParent && !element.contains(expectedParent) &&
|
|
1861
|
-
|
|
1862
|
+
getExpectedParagraphTrackId(trackedElements, parentTrackId)) {
|
|
1862
1863
|
displacedElements.add(element);
|
|
1863
1864
|
}
|
|
1864
1865
|
});
|
|
1865
|
-
const insertedParagraphs = new
|
|
1866
|
+
const insertedParagraphs = new Map();
|
|
1866
1867
|
displacedElements.forEach(element => {
|
|
1867
1868
|
let sibling = element.nextSibling;
|
|
1868
1869
|
while (sibling && (sibling.nodeType != 1 || displacedElements.has(sibling))) {
|
|
1869
1870
|
sibling = sibling.nextSibling;
|
|
1870
1871
|
}
|
|
1871
1872
|
if (sibling && sibling.tagName == PARAGRAPH_TAG_NAME && !sibling.attributes.length && !sibling.childNodes.length) {
|
|
1872
|
-
|
|
1873
|
+
const trackId = element.getAttribute(util.NESTING_TRACK_ID_ATTRIBUTE_NAME);
|
|
1874
|
+
insertedParagraphs.set(sibling, getExpectedParagraphTrackId(trackedElements, getParentTrackId(trackId)));
|
|
1873
1875
|
}
|
|
1874
1876
|
});
|
|
1875
|
-
insertedParagraphs
|
|
1877
|
+
return insertedParagraphs;
|
|
1876
1878
|
}
|
|
1877
1879
|
|
|
1878
|
-
function
|
|
1880
|
+
function getExpectedParagraphTrackId(trackedElements, trackId) {
|
|
1879
1881
|
let element = trackedElements.get(trackId);
|
|
1880
1882
|
while (element) {
|
|
1881
1883
|
if (element.tagName == PARAGRAPH_TAG_NAME) {
|
|
1882
|
-
return
|
|
1884
|
+
return trackId;
|
|
1883
1885
|
}
|
|
1884
1886
|
trackId = getParentTrackId(trackId);
|
|
1885
1887
|
element = trackId ? trackedElements.get(trackId) : null;
|
|
1886
1888
|
}
|
|
1887
|
-
return false;
|
|
1888
1889
|
}
|
|
1889
1890
|
|
|
1890
1891
|
function getParentTrackId(trackId) {
|
package/core/util.js
CHANGED
|
@@ -185,8 +185,8 @@ function getInstance(utilOptions) {
|
|
|
185
185
|
postProcessDoc(doc, markedElements, invalidElements) {
|
|
186
186
|
helper.postProcessDoc(doc, markedElements, invalidElements);
|
|
187
187
|
},
|
|
188
|
-
serialize(doc, compressHTML) {
|
|
189
|
-
return modules.serializer.process(doc, compressHTML);
|
|
188
|
+
serialize(doc, compressHTML, omittedEndTagElements) {
|
|
189
|
+
return modules.serializer.process(doc, compressHTML, omittedEndTagElements);
|
|
190
190
|
},
|
|
191
191
|
removeQuotes(string) {
|
|
192
192
|
return helper.removeQuotes(string);
|
|
@@ -59,7 +59,7 @@ export {
|
|
|
59
59
|
process
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
-
function process(doc, compressHTML) {
|
|
62
|
+
function process(doc, compressHTML, omittedEndTagElements) {
|
|
63
63
|
const docType = doc.doctype;
|
|
64
64
|
let docTypeString = "";
|
|
65
65
|
if (docType) {
|
|
@@ -74,16 +74,16 @@ function process(doc, compressHTML) {
|
|
|
74
74
|
docTypeString += " [" + docType.internalSubset + "]";
|
|
75
75
|
docTypeString += "> ";
|
|
76
76
|
}
|
|
77
|
-
return docTypeString + serialize(doc.documentElement, compressHTML);
|
|
77
|
+
return docTypeString + serialize(doc.documentElement, compressHTML, omittedEndTagElements);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
function serialize(node, compressHTML) {
|
|
80
|
+
function serialize(node, compressHTML, omittedEndTagElements) {
|
|
81
81
|
if (node.nodeType == Node_TEXT_NODE) {
|
|
82
82
|
return serializeTextNode(node);
|
|
83
83
|
} else if (node.nodeType == Node_COMMENT_NODE) {
|
|
84
84
|
return serializeCommentNode(node);
|
|
85
85
|
} else if (node.nodeType == Node_ELEMENT_NODE) {
|
|
86
|
-
return serializeElement(node, compressHTML);
|
|
86
|
+
return serializeElement(node, compressHTML, omittedEndTagElements);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
@@ -95,7 +95,7 @@ function serializeTextNode(textNode) {
|
|
|
95
95
|
}
|
|
96
96
|
if (!parentTagName || TEXT_NODE_TAGS.includes(parentTagName)) {
|
|
97
97
|
if ((parentTagName == "SCRIPT" && (!parentNode.type || parentNode.type == "text/javascript")) || parentTagName == "STYLE") {
|
|
98
|
-
return textNode.textContent.replace(/<\//gi, "<\\/")
|
|
98
|
+
return textNode.textContent.replace(/<\//gi, "<\\/");
|
|
99
99
|
}
|
|
100
100
|
return textNode.textContent;
|
|
101
101
|
} else {
|
|
@@ -107,7 +107,7 @@ function serializeCommentNode(commentNode) {
|
|
|
107
107
|
return "<!--" + commentNode.textContent + "-->";
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
function serializeElement(element, compressHTML) {
|
|
110
|
+
function serializeElement(element, compressHTML, omittedEndTagElements) {
|
|
111
111
|
const tagName = getTagName(element);
|
|
112
112
|
const omittedStartTag = compressHTML && OMITTED_START_TAGS.find(omittedStartTag => tagName == getTagName(omittedStartTag) && omittedStartTag.accept(element));
|
|
113
113
|
let content = "";
|
|
@@ -119,9 +119,9 @@ function serializeElement(element, compressHTML) {
|
|
|
119
119
|
if (tagName == "TEMPLATE" && !element.childNodes.length) {
|
|
120
120
|
content += element.innerHTML;
|
|
121
121
|
} else {
|
|
122
|
-
Array.from(element.childNodes).forEach(childNode => content += serialize(childNode, compressHTML));
|
|
122
|
+
Array.from(element.childNodes).forEach(childNode => content += serialize(childNode, compressHTML, omittedEndTagElements));
|
|
123
123
|
}
|
|
124
|
-
const omittedEndTag = compressHTML && OMITTED_END_TAGS.find(omittedEndTag => tagName == getTagName(omittedEndTag) && omittedEndTag.accept(element.nextSibling, element));
|
|
124
|
+
const omittedEndTag = (omittedEndTagElements && omittedEndTagElements.has(element)) || compressHTML && OMITTED_END_TAGS.find(omittedEndTag => tagName == getTagName(omittedEndTag) && omittedEndTag.accept(element.nextSibling, element));
|
|
125
125
|
if (!omittedEndTag && !VOID_TAG_NAMES.includes(tagName)) {
|
|
126
126
|
content += "</" + tagName.toLowerCase() + ">";
|
|
127
127
|
}
|