single-file-core 1.0.22 → 1.0.24

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.
@@ -36,7 +36,9 @@ class MatchedRules {
36
36
  this.mediaAllInfo = createMediaInfo(MEDIA_ALL);
37
37
  const matchedElementsCache = new Map();
38
38
  let sheetIndex = 0;
39
- const workStyleElement = doc.createElement("style");
39
+ const workStyleSheet = doc.createElement("style");
40
+ doc.body.appendChild(workStyleSheet);
41
+ const workStyleElement = doc.createElement("span");
40
42
  doc.body.appendChild(workStyleElement);
41
43
  stylesheets.forEach(stylesheetInfo => {
42
44
  if (!stylesheetInfo.scoped) {
@@ -45,9 +47,9 @@ class MatchedRules {
45
47
  if (stylesheetInfo.mediaText && stylesheetInfo.mediaText != MEDIA_ALL) {
46
48
  const mediaInfo = createMediaInfo(stylesheetInfo.mediaText);
47
49
  this.mediaAllInfo.medias.set("style-" + sheetIndex + "-" + stylesheetInfo.mediaText, mediaInfo);
48
- getMatchedElementsRules(doc, cssRules, mediaInfo, sheetIndex, styles, matchedElementsCache, workStyleElement);
50
+ getMatchedElementsRules(doc, cssRules, mediaInfo, sheetIndex, styles, matchedElementsCache, workStyleSheet);
49
51
  } else {
50
- getMatchedElementsRules(doc, cssRules, this.mediaAllInfo, sheetIndex, styles, matchedElementsCache, workStyleElement);
52
+ getMatchedElementsRules(doc, cssRules, this.mediaAllInfo, sheetIndex, styles, matchedElementsCache, workStyleSheet);
51
53
  }
52
54
  }
53
55
  }
@@ -64,7 +66,8 @@ class MatchedRules {
64
66
  startTime = Date.now();
65
67
  log(" -- STARTED computeCascade");
66
68
  }
67
- computeCascade(this.mediaAllInfo, [], this.mediaAllInfo, workStyleElement);
69
+ computeCascade(this.mediaAllInfo, [], this.mediaAllInfo, workStyleSheet, workStyleElement);
70
+ workStyleSheet.remove();
68
71
  workStyleElement.remove();
69
72
  if (DEBUG) {
70
73
  log(" -- ENDED computeCascade", Date.now() - startTime);
@@ -222,9 +225,9 @@ function addRule(element, selectorInfo, styles) {
222
225
  elementInfo.push(selectorInfo);
223
226
  }
224
227
 
225
- function computeCascade(mediaInfo, parentMediaInfo, mediaAllInfo, workStylesheet) {
228
+ function computeCascade(mediaInfo, parentMediaInfo, mediaAllInfo, workStylesheet, workStyleElement) {
226
229
  mediaInfo.elements.forEach((elementInfo/*, element*/) =>
227
- getDeclarationsInfo(elementInfo, workStylesheet/*, element*/).forEach((declarationsInfo, property) => {
230
+ getDeclarationsInfo(elementInfo, workStylesheet, workStyleElement/*, element*/).forEach((declarationsInfo, property) => {
228
231
  if (declarationsInfo.selectorInfo.ruleInfo || mediaInfo == mediaAllInfo) {
229
232
  let info;
230
233
  if (declarationsInfo.selectorInfo.ruleInfo) {
@@ -249,10 +252,10 @@ function computeCascade(mediaInfo, parentMediaInfo, mediaAllInfo, workStylesheet
249
252
  }
250
253
  }));
251
254
  delete mediaInfo.elements;
252
- mediaInfo.medias.forEach(childMediaInfo => computeCascade(childMediaInfo, [mediaInfo, ...parentMediaInfo], mediaAllInfo, workStylesheet));
255
+ mediaInfo.medias.forEach(childMediaInfo => computeCascade(childMediaInfo, [mediaInfo, ...parentMediaInfo], mediaAllInfo, workStylesheet, workStyleElement));
253
256
  }
254
257
 
255
- function getDeclarationsInfo(elementInfo, workStylesheet/*, element*/) {
258
+ function getDeclarationsInfo(elementInfo, workStylesheet, workStyleElement/*, element*/) {
256
259
  const declarationsInfo = new Map();
257
260
  const processedProperties = new Set();
258
261
  elementInfo.forEach(selectorInfo => {
@@ -262,17 +265,17 @@ function getDeclarationsInfo(elementInfo, workStylesheet/*, element*/) {
262
265
  } else {
263
266
  declarations = selectorInfo.ruleInfo.ruleData.block.children;
264
267
  }
265
- processDeclarations(declarationsInfo, declarations, selectorInfo, processedProperties, workStylesheet);
268
+ processDeclarations(declarationsInfo, declarations, selectorInfo, processedProperties, workStylesheet, workStyleElement);
266
269
  });
267
270
  return declarationsInfo;
268
271
  }
269
272
 
270
- function processDeclarations(declarationsInfo, declarations, selectorInfo, processedProperties, workStylesheet) {
273
+ function processDeclarations(declarationsInfo, declarations, selectorInfo, processedProperties, workStylesheet, workStyleElement) {
271
274
  for (let declaration = declarations.tail; declaration; declaration = declaration.prev) {
272
275
  const declarationData = declaration.data;
273
276
  const declarationText = cssTree.generate(declarationData);
274
277
  if (declarationData.type == "Declaration" &&
275
- (declarationText.match(REGEXP_VENDOR_IDENTIFIER) || !processedProperties.has(declarationData.property) || declarationData.important) && !invalidDeclaration(declarationText, workStylesheet)) {
278
+ (declarationText.match(REGEXP_VENDOR_IDENTIFIER) || !processedProperties.has(declarationData.property) || declarationData.important) && !invalidDeclaration(declarationText, workStyleElement)) {
276
279
  const declarationInfo = declarationsInfo.get(declarationData);
277
280
  if (!declarationInfo || (declarationData.important && !declarationInfo.important)) {
278
281
  declarationsInfo.set(declarationData, { selectorInfo, important: declarationData.important });
@@ -284,10 +287,10 @@ function processDeclarations(declarationsInfo, declarations, selectorInfo, proce
284
287
  }
285
288
  }
286
289
 
287
- function invalidDeclaration(declarationText, workStylesheet) {
290
+ function invalidDeclaration(declarationText, workStyleElement) {
288
291
  let invalidDeclaration;
289
- workStylesheet.textContent = "single-file-declaration { " + declarationText + "}";
290
- if (workStylesheet.sheet && !workStylesheet.sheet.cssRules[0].style.length) {
292
+ workStyleElement.style = declarationText;
293
+ if (!workStyleElement.style.length) {
291
294
  if (!declarationText.match(REGEXP_VENDOR_IDENTIFIER)) {
292
295
  invalidDeclaration = true;
293
296
  }
@@ -101,9 +101,13 @@ function setSrc(srcData, imgElement, pictureElement) {
101
101
 
102
102
  function getSourceSrc(sourceSrcSet) {
103
103
  if (sourceSrcSet) {
104
- const srcset = srcsetParser.process(sourceSrcSet);
105
- if (srcset.length) {
106
- return (srcset.find(srcset => srcset.url)).url;
104
+ try {
105
+ const srcset = srcsetParser.process(sourceSrcSet);
106
+ if (srcset.length) {
107
+ return (srcset.find(srcset => srcset.url)).url;
108
+ }
109
+ } catch (error) {
110
+ // ignored
107
111
  }
108
112
  }
109
113
  }
@@ -145,7 +145,7 @@ function serializeAttribute(attribute, element, compressHTML) {
145
145
  simpleQuotesValue = true;
146
146
  }
147
147
  }
148
- const invalidUnquotedValue = !compressHTML || !value.match(/^[^ \t\n\f\r'"`=<>]+$/);
148
+ const invalidUnquotedValue = !compressHTML || value.match(/[ \t\n\f\r'"`=<>]/);
149
149
  content += " ";
150
150
  if (!attribute.namespace) {
151
151
  content += name;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "single-file-core",
3
- "version": "1.0.22",
3
+ "version": "1.0.24",
4
4
  "description": "SingleFile Core",
5
5
  "author": "Gildas Lormeau",
6
6
  "license": "AGPL-3.0-or-later",
@@ -1854,10 +1854,6 @@ class ProcessorHelper {
1854
1854
  if (testValidURL(resourceURL)) {
1855
1855
  let { content, indexResource, duplicate } = await batchRequest.addURL(resourceURL,
1856
1856
  { asBinary: true, expectedType, groupDuplicates: options.groupDuplicateImages && resourceElement.tagName == "IMG" && attributeName == "src" });
1857
- if (resourceURL.includes("openbenchmarking.org/embed.php")) {
1858
- debugger
1859
- }
1860
-
1861
1857
  if (originURL) {
1862
1858
  if (content == util.EMPTY_RESOURCE) {
1863
1859
  try {
@@ -148,7 +148,7 @@ function preProcessDoc(doc, win, options) {
148
148
  elementsInfo = getElementsInfo(win, doc, doc.documentElement, options);
149
149
  if (options.moveStylesInHead) {
150
150
  doc.querySelectorAll("body style, body ~ style").forEach(element => {
151
- const computedStyle = win.getComputedStyle(element);
151
+ const computedStyle = getComputedStyle(win, element);
152
152
  if (computedStyle && testHiddenElement(element, computedStyle)) {
153
153
  element.setAttribute(STYLE_ATTRIBUTE_NAME, "");
154
154
  elementsInfo.markedElements.push(element);
@@ -186,7 +186,7 @@ function getElementsInfo(win, doc, element, options, data = { usedFonts: new Map
186
186
  elements.forEach(element => {
187
187
  let elementHidden, elementKept, computedStyle;
188
188
  if (!options.autoSaveExternalSave && (options.removeHiddenElements || options.removeUnusedFonts || options.compressHTML)) {
189
- computedStyle = win.getComputedStyle(element);
189
+ computedStyle = getComputedStyle(win, element);
190
190
  if (element instanceof win.HTMLElement) {
191
191
  if (options.removeHiddenElements) {
192
192
  elementKept = ((ascendantHidden || element.closest("html > head")) && KEPT_TAG_NAMES.includes(element.tagName)) || element.closest("details");
@@ -209,9 +209,9 @@ function getElementsInfo(win, doc, element, options, data = { usedFonts: new Map
209
209
  }
210
210
  if (options.removeUnusedFonts) {
211
211
  getUsedFont(computedStyle, options, data.usedFonts);
212
- getUsedFont(win.getComputedStyle(element, ":first-letter"), options, data.usedFonts);
213
- getUsedFont(win.getComputedStyle(element, ":before"), options, data.usedFonts);
214
- getUsedFont(win.getComputedStyle(element, ":after"), options, data.usedFonts);
212
+ getUsedFont(getComputedStyle(win, element, ":first-letter"), options, data.usedFonts);
213
+ getUsedFont(getComputedStyle(win, element, ":before"), options, data.usedFonts);
214
+ getUsedFont(getComputedStyle(win, element, ":after"), options, data.usedFonts);
215
215
  }
216
216
  }
217
217
  }
@@ -269,11 +269,7 @@ function getResourcesInfo(win, doc, element, options, data, elementHidden, compu
269
269
  element.setAttribute(IMAGE_ATTRIBUTE_NAME, data.images.length - 1);
270
270
  data.markedElements.push(element);
271
271
  element.removeAttribute(LAZY_SRC_ATTRIBUTE_NAME);
272
- try {
273
- computedStyle = computedStyle || win.getComputedStyle(element);
274
- } catch (error) {
275
- // ignored
276
- }
272
+ computedStyle = computedStyle || getComputedStyle(win, element);
277
273
  if (computedStyle) {
278
274
  imageData.size = getSize(win, element, computedStyle);
279
275
  const boxShadow = computedStyle.getPropertyValue("box-shadow");
@@ -292,9 +288,9 @@ function getResourcesInfo(win, doc, element, options, data, elementHidden, compu
292
288
  if (element.tagName == "VIDEO") {
293
289
  const src = element.currentSrc;
294
290
  if (src && !src.startsWith("blob:") && !src.startsWith("data:")) {
295
- const positionParent = win.getComputedStyle(element.parentNode).getPropertyValue("position");
291
+ const computedStyle = getComputedStyle(win, element.parentNode);
296
292
  data.videos.push({
297
- positionParent,
293
+ positionParent: computedStyle && computedStyle.getPropertyValue("position"),
298
294
  src,
299
295
  size: {
300
296
  pxWidth: element.clientWidth,
@@ -469,37 +465,39 @@ function getSize(win, imageElement, computedStyle) {
469
465
  let pxHeight = imageElement.naturalHeight;
470
466
  if (!pxWidth && !pxHeight) {
471
467
  const noStyleAttribute = imageElement.getAttribute("style") == null;
472
- computedStyle = computedStyle || win.getComputedStyle(imageElement);
473
- let removeBorderWidth = false;
474
- if (computedStyle.getPropertyValue("box-sizing") == "content-box") {
475
- const boxSizingValue = imageElement.style.getPropertyValue("box-sizing");
476
- const boxSizingPriority = imageElement.style.getPropertyPriority("box-sizing");
477
- const clientWidth = imageElement.clientWidth;
478
- imageElement.style.setProperty("box-sizing", "border-box", "important");
479
- removeBorderWidth = imageElement.clientWidth != clientWidth;
480
- if (boxSizingValue) {
481
- imageElement.style.setProperty("box-sizing", boxSizingValue, boxSizingPriority);
468
+ computedStyle = computedStyle || getComputedStyle(win, imageElement);
469
+ if (computedStyle) {
470
+ let removeBorderWidth = false;
471
+ if (computedStyle.getPropertyValue("box-sizing") == "content-box") {
472
+ const boxSizingValue = imageElement.style.getPropertyValue("box-sizing");
473
+ const boxSizingPriority = imageElement.style.getPropertyPriority("box-sizing");
474
+ const clientWidth = imageElement.clientWidth;
475
+ imageElement.style.setProperty("box-sizing", "border-box", "important");
476
+ removeBorderWidth = imageElement.clientWidth != clientWidth;
477
+ if (boxSizingValue) {
478
+ imageElement.style.setProperty("box-sizing", boxSizingValue, boxSizingPriority);
479
+ } else {
480
+ imageElement.style.removeProperty("box-sizing");
481
+ }
482
+ }
483
+ let paddingLeft, paddingRight, paddingTop, paddingBottom, borderLeft, borderRight, borderTop, borderBottom;
484
+ paddingLeft = getWidth("padding-left", computedStyle);
485
+ paddingRight = getWidth("padding-right", computedStyle);
486
+ paddingTop = getWidth("padding-top", computedStyle);
487
+ paddingBottom = getWidth("padding-bottom", computedStyle);
488
+ if (removeBorderWidth) {
489
+ borderLeft = getWidth("border-left-width", computedStyle);
490
+ borderRight = getWidth("border-right-width", computedStyle);
491
+ borderTop = getWidth("border-top-width", computedStyle);
492
+ borderBottom = getWidth("border-bottom-width", computedStyle);
482
493
  } else {
483
- imageElement.style.removeProperty("box-sizing");
494
+ borderLeft = borderRight = borderTop = borderBottom = 0;
495
+ }
496
+ pxWidth = Math.max(0, imageElement.clientWidth - paddingLeft - paddingRight - borderLeft - borderRight);
497
+ pxHeight = Math.max(0, imageElement.clientHeight - paddingTop - paddingBottom - borderTop - borderBottom);
498
+ if (noStyleAttribute) {
499
+ imageElement.removeAttribute("style");
484
500
  }
485
- }
486
- let paddingLeft, paddingRight, paddingTop, paddingBottom, borderLeft, borderRight, borderTop, borderBottom;
487
- paddingLeft = getWidth("padding-left", computedStyle);
488
- paddingRight = getWidth("padding-right", computedStyle);
489
- paddingTop = getWidth("padding-top", computedStyle);
490
- paddingBottom = getWidth("padding-bottom", computedStyle);
491
- if (removeBorderWidth) {
492
- borderLeft = getWidth("border-left-width", computedStyle);
493
- borderRight = getWidth("border-right-width", computedStyle);
494
- borderTop = getWidth("border-top-width", computedStyle);
495
- borderBottom = getWidth("border-bottom-width", computedStyle);
496
- } else {
497
- borderLeft = borderRight = borderTop = borderBottom = 0;
498
- }
499
- pxWidth = Math.max(0, imageElement.clientWidth - paddingLeft - paddingRight - borderLeft - borderRight);
500
- pxHeight = Math.max(0, imageElement.clientHeight - paddingTop - paddingBottom - borderTop - borderBottom);
501
- if (noStyleAttribute) {
502
- imageElement.removeAttribute("style");
503
501
  }
504
502
  }
505
503
  return { pxWidth, pxHeight };
@@ -550,4 +548,12 @@ function getFontWeight(weight) {
550
548
 
551
549
  function flatten(array) {
552
550
  return array.flat ? array.flat() : array.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []);
551
+ }
552
+
553
+ function getComputedStyle(win, element, pseudoElement) {
554
+ try {
555
+ return win.getComputedStyle(element, pseudoElement);
556
+ } catch (error) {
557
+ // ignored
558
+ }
553
559
  }