single-file-core 1.5.16 → 1.5.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/core/index.js CHANGED
@@ -1176,6 +1176,20 @@ class Processor {
1176
1176
  }
1177
1177
 
1178
1178
  async resolveStylesheetsURLs() {
1179
+ const scriptContents = [];
1180
+ this.options.inlineStylesheets = new Map();
1181
+ this.options.inlineStylesheetsRefs = new Map();
1182
+ this.doc.querySelectorAll("style").forEach(element => {
1183
+ if (element.textContent) {
1184
+ const indexContent = scriptContents.indexOf(element.textContent);
1185
+ if (indexContent == -1) {
1186
+ this.options.inlineStylesheets.set(scriptContents.length, element);
1187
+ scriptContents.push(element.textContent);
1188
+ } else {
1189
+ this.options.inlineStylesheetsRefs.set(element, indexContent);
1190
+ }
1191
+ }
1192
+ });
1179
1193
  await Promise.all(Array.from(this.doc.querySelectorAll("style, link[rel*=stylesheet]")).map(async element => {
1180
1194
  const options = Object.assign({}, this.options, { charset: this.charset });
1181
1195
  let mediaText;
@@ -1364,9 +1378,11 @@ class Processor {
1364
1378
  }
1365
1379
 
1366
1380
  async processStylesheets() {
1367
- await Promise.all([...this.stylesheets].map(([, stylesheetInfo]) =>
1368
- this.processorHelper.processStylesheet(stylesheetInfo.stylesheet.children, this.baseURI, this.options, this.resources, this.batchRequest)
1369
- ));
1381
+ await Promise.all([...this.stylesheets].map(async ([, stylesheetInfo]) => {
1382
+ if (stylesheetInfo.stylesheet) {
1383
+ await this.processorHelper.processStylesheet(stylesheetInfo.stylesheet.children, this.baseURI, this.options, this.resources, this.batchRequest);
1384
+ }
1385
+ }));
1370
1386
  }
1371
1387
 
1372
1388
  async processStyleAttributes() {
@@ -1457,6 +1473,8 @@ class Processor {
1457
1473
 
1458
1474
  replaceStylesheets() {
1459
1475
  this.processorHelper.replaceStylesheets(this.doc, this.stylesheets, this.options, this.resources);
1476
+ delete this.options.inlineStylesheetsRefs;
1477
+ delete this.options.inlineStylesheets;
1460
1478
  }
1461
1479
 
1462
1480
  replaceStyleAttributes() {
@@ -402,31 +402,35 @@ class ProcessorHelperCommon {
402
402
  const stats = { rules: { processed: 0, discarded: 0 }, fonts: { processed: 0, discarded: 0 } };
403
403
  let sheetIndex = 0;
404
404
  stylesheets.forEach(stylesheetInfo => {
405
- const cssRules = stylesheetInfo.stylesheet.children;
406
- if (cssRules) {
407
- stats.rules.processed += cssRules.size;
408
- stats.rules.discarded += cssRules.size;
409
- if (stylesheetInfo.mediaText && stylesheetInfo.mediaText != MEDIA_ALL) {
410
- const mediaFontsDetails = this.createFontsDetailsInfo();
411
- fontsDetails.medias.set("media-" + sheetIndex + "-" + stylesheetInfo.mediaText, mediaFontsDetails);
412
- this.getFontsDetails(doc, cssRules, sheetIndex, mediaFontsDetails);
413
- } else {
414
- this.getFontsDetails(doc, cssRules, sheetIndex, fontsDetails);
405
+ if (stylesheetInfo.stylesheet) {
406
+ const cssRules = stylesheetInfo.stylesheet.children;
407
+ if (cssRules) {
408
+ stats.rules.processed += cssRules.size;
409
+ stats.rules.discarded += cssRules.size;
410
+ if (stylesheetInfo.mediaText && stylesheetInfo.mediaText != MEDIA_ALL) {
411
+ const mediaFontsDetails = this.createFontsDetailsInfo();
412
+ fontsDetails.medias.set("media-" + sheetIndex + "-" + stylesheetInfo.mediaText, mediaFontsDetails);
413
+ this.getFontsDetails(doc, cssRules, sheetIndex, mediaFontsDetails);
414
+ } else {
415
+ this.getFontsDetails(doc, cssRules, sheetIndex, fontsDetails);
416
+ }
415
417
  }
416
418
  }
417
419
  sheetIndex++;
418
420
  });
419
421
  processFontDetails(fontsDetails);
420
422
  await Promise.all([...stylesheets].map(async ([, stylesheetInfo], sheetIndex) => {
421
- const cssRules = stylesheetInfo.stylesheet.children;
422
- const media = stylesheetInfo.mediaText;
423
- if (cssRules) {
424
- if (media && media != MEDIA_ALL) {
425
- await this.processFontFaceRules(cssRules, sheetIndex, fontsDetails.medias.get("media-" + sheetIndex + "-" + media), fonts, fontTests, stats);
426
- } else {
427
- await this.processFontFaceRules(cssRules, sheetIndex, fontsDetails, fonts, fontTests, stats);
423
+ if (stylesheetInfo.stylesheet) {
424
+ const cssRules = stylesheetInfo.stylesheet.children;
425
+ const media = stylesheetInfo.mediaText;
426
+ if (cssRules) {
427
+ if (media && media != MEDIA_ALL) {
428
+ await this.processFontFaceRules(cssRules, sheetIndex, fontsDetails.medias.get("media-" + sheetIndex + "-" + media), fonts, fontTests, stats);
429
+ } else {
430
+ await this.processFontFaceRules(cssRules, sheetIndex, fontsDetails, fonts, fontTests, stats);
431
+ }
432
+ stats.rules.discarded -= cssRules.size;
428
433
  }
429
- stats.rules.discarded -= cssRules.size;
430
434
  }
431
435
  }));
432
436
  return stats;
@@ -83,25 +83,27 @@ function getProcessorHelperClass(utilInstance) {
83
83
  async resolveStylesheetElement(element, stylesheetInfo, stylesheets, baseURI, options, workStyleElement) {
84
84
  let stylesheet;
85
85
  stylesheets.set(element, stylesheetInfo);
86
- if (!options.blockStylesheets) {
87
- if (element.tagName.toUpperCase() == "LINK") {
88
- stylesheet = await this.resolveLinkStylesheetURLs(element.href, baseURI, options, workStyleElement);
89
- } else {
90
- stylesheet = cssTree.parse(element.textContent, { context: "stylesheet", parseCustomProperty: true });
91
- const importFound = await this.resolveImportURLs(stylesheet, baseURI, options, workStyleElement);
92
- if (importFound) {
93
- stylesheet = cssTree.parse(cssTree.generate(stylesheet), { context: "stylesheet", parseCustomProperty: true });
86
+ if (!options.inlineStylesheetsRefs.has(element)) {
87
+ if (!options.blockStylesheets) {
88
+ if (element.tagName.toUpperCase() == "LINK") {
89
+ stylesheet = await this.resolveLinkStylesheetURLs(element.href, baseURI, options, workStyleElement);
90
+ } else {
91
+ stylesheet = cssTree.parse(element.textContent, { context: "stylesheet", parseCustomProperty: true });
92
+ const importFound = await this.resolveImportURLs(stylesheet, baseURI, options, workStyleElement);
93
+ if (importFound) {
94
+ stylesheet = cssTree.parse(cssTree.generate(stylesheet), { context: "stylesheet", parseCustomProperty: true });
95
+ }
94
96
  }
95
97
  }
96
- }
97
- if (stylesheet && stylesheet.children) {
98
- if (options.compressCSS) {
99
- this.removeSingleLineCssComments(stylesheet);
98
+ if (stylesheet && stylesheet.children) {
99
+ if (options.compressCSS) {
100
+ this.removeSingleLineCssComments(stylesheet);
101
+ }
102
+ this.replacePseudoClassDefined(stylesheet);
103
+ stylesheetInfo.stylesheet = stylesheet;
104
+ } else {
105
+ stylesheets.delete(element);
100
106
  }
101
- this.replacePseudoClassDefined(stylesheet);
102
- stylesheetInfo.stylesheet = stylesheet;
103
- } else {
104
- stylesheets.delete(element);
105
107
  }
106
108
  }
107
109
 
@@ -110,7 +112,13 @@ function getProcessorHelperClass(utilInstance) {
110
112
  const stylesheetInfo = stylesheets.get(styleElement);
111
113
  if (stylesheetInfo) {
112
114
  stylesheets.delete(styleElement);
113
- styleElement.textContent = this.generateStylesheetContent(stylesheetInfo.stylesheet, options);
115
+ const styleSheetRefIndex = options.inlineStylesheetsRefs.get(styleElement);
116
+ if (styleSheetRefIndex === undefined) {
117
+ styleElement.textContent = this.generateStylesheetContent(stylesheetInfo.stylesheet, options);
118
+ } else {
119
+ const styleElementRef = options.inlineStylesheets.get(styleSheetRefIndex);
120
+ styleElement.textContent = styleElementRef.textContent;
121
+ }
114
122
  if (stylesheetInfo.mediaText) {
115
123
  styleElement.media = stylesheetInfo.mediaText;
116
124
  }
@@ -76,19 +76,21 @@ function getProcessorHelperClass(utilInstance) {
76
76
  }
77
77
 
78
78
  async resolveStylesheetElement(element, stylesheetInfo, stylesheets, baseURI, options, workStyleElement, resources) {
79
- if (!options.blockStylesheets) {
80
- stylesheets.set({ element }, stylesheetInfo);
81
- if (element.tagName.toUpperCase() == "LINK") {
82
- await this.resolveLinkStylesheetURLs(stylesheetInfo, element, element.href, baseURI, options, workStyleElement, resources, stylesheets);
83
- } else {
84
- stylesheetInfo.stylesheet = cssTree.parse(element.textContent, { context: "stylesheet", parseCustomProperty: true });
85
- await this.resolveImportURLs(stylesheetInfo, baseURI, options, workStyleElement, resources, stylesheets);
86
- }
87
- } else {
88
- if (element.tagName.toUpperCase() == "LINK") {
89
- element.href = util.EMPTY_RESOURCE;
79
+ if (!options.inlineStylesheetsRefs.has(element)) {
80
+ if (!options.blockStylesheets) {
81
+ stylesheets.set({ element }, stylesheetInfo);
82
+ if (element.tagName.toUpperCase() == "LINK") {
83
+ await this.resolveLinkStylesheetURLs(stylesheetInfo, element, element.href, baseURI, options, workStyleElement, resources, stylesheets);
84
+ } else {
85
+ stylesheetInfo.stylesheet = cssTree.parse(element.textContent, { context: "stylesheet", parseCustomProperty: true });
86
+ await this.resolveImportURLs(stylesheetInfo, baseURI, options, workStyleElement, resources, stylesheets);
87
+ }
90
88
  } else {
91
- element.textContent = "";
89
+ if (element.tagName.toUpperCase() == "LINK") {
90
+ element.href = util.EMPTY_RESOURCE;
91
+ } else {
92
+ element.textContent = "";
93
+ }
92
94
  }
93
95
  }
94
96
  }
@@ -112,7 +114,13 @@ function getProcessorHelperClass(utilInstance) {
112
114
  resources.stylesheets.set(resources.stylesheets.size, { name, stylesheet: stylesheetInfo.stylesheet });
113
115
  } else {
114
116
  const styleElement = key.element;
115
- styleElement.textContent = this.generateStylesheetContent(stylesheetInfo.stylesheet, options);
117
+ const styleSheetRefIndex = options.inlineStylesheetsRefs.get(styleElement);
118
+ if (styleSheetRefIndex === undefined) {
119
+ styleElement.textContent = this.generateStylesheetContent(stylesheetInfo.stylesheet, options);
120
+ } else {
121
+ const styleElementRef = options.inlineStylesheets.get(styleSheetRefIndex);
122
+ styleElement.textContent = styleElementRef.textContent;
123
+ }
116
124
  }
117
125
  }
118
126
  }
@@ -56,12 +56,14 @@ function process(doc, stylesheets, styles, options) {
56
56
  let docContent = "";
57
57
  doc.body.appendChild(workStyleElement);
58
58
  stylesheets.forEach(stylesheetInfo => {
59
- const cssRules = stylesheetInfo.stylesheet.children;
60
- if (cssRules) {
61
- stats.processed += cssRules.size;
62
- stats.discarded += cssRules.size;
63
- getFontsInfo(cssRules, fontsInfo, options);
64
- docContent = getRulesTextContent(doc, cssRules, workStyleElement, docContent);
59
+ if (stylesheetInfo.stylesheet) {
60
+ const cssRules = stylesheetInfo.stylesheet.children;
61
+ if (cssRules) {
62
+ stats.processed += cssRules.size;
63
+ stats.discarded += cssRules.size;
64
+ getFontsInfo(cssRules, fontsInfo, options);
65
+ docContent = getRulesTextContent(doc, cssRules, workStyleElement, docContent);
66
+ }
65
67
  }
66
68
  });
67
69
  styles.forEach(declarations => {
@@ -102,10 +104,12 @@ function process(doc, stylesheets, styles, options) {
102
104
  }
103
105
  const docChars = Array.from(new Set(docContent)).map(char => char.charCodeAt(0)).sort((value1, value2) => value1 - value2);
104
106
  stylesheets.forEach(stylesheetInfo => {
105
- const cssRules = stylesheetInfo.stylesheet.children;
106
- if (cssRules) {
107
- filterUnusedFonts(cssRules, fontsInfo.declared, unusedFonts, filteredUsedFonts, docChars);
108
- stats.rules.discarded -= cssRules.size;
107
+ if (stylesheetInfo.stylesheet) {
108
+ const cssRules = stylesheetInfo.stylesheet.children;
109
+ if (cssRules) {
110
+ filterUnusedFonts(cssRules, fontsInfo.declared, unusedFonts, filteredUsedFonts, docChars);
111
+ stats.rules.discarded -= cssRules.size;
112
+ }
109
113
  }
110
114
  });
111
115
  return stats;
@@ -41,7 +41,7 @@ class MatchedRules {
41
41
  const workStyleElement = doc.createElement("span");
42
42
  doc.body.appendChild(workStyleElement);
43
43
  stylesheets.forEach((stylesheetInfo, key) => {
44
- if (!stylesheetInfo.scoped && !key.urlNode) {
44
+ if (!stylesheetInfo.scoped && stylesheetInfo.stylesheet && !key.urlNode) {
45
45
  const cssRules = stylesheetInfo.stylesheet.children;
46
46
  if (cssRules) {
47
47
  if (stylesheetInfo.mediaText && stylesheetInfo.mediaText != MEDIA_ALL) {
@@ -39,13 +39,15 @@ export {
39
39
  function process(stylesheets) {
40
40
  const stats = { processed: 0, discarded: 0 };
41
41
  stylesheets.forEach((stylesheetInfo, key) => {
42
- if (matchesMediaType(stylesheetInfo.mediaText || MEDIA_ALL) && stylesheetInfo.stylesheet.children) {
43
- const removedRules = processRules(stylesheetInfo.stylesheet.children, stats);
44
- removedRules.forEach(({ cssRules, cssRule }) => cssRules.remove(cssRule));
45
- } else {
46
- stylesheets.delete(key);
47
- if (key.element) {
48
- key.element.remove();
42
+ if (stylesheetInfo.stylesheet) {
43
+ if (matchesMediaType(stylesheetInfo.mediaText || MEDIA_ALL) && stylesheetInfo.stylesheet.children) {
44
+ const removedRules = processRules(stylesheetInfo.stylesheet.children, stats);
45
+ removedRules.forEach(({ cssRules, cssRule }) => cssRules.remove(cssRule));
46
+ } else {
47
+ stylesheets.delete(key);
48
+ if (key.element) {
49
+ key.element.remove();
50
+ }
49
51
  }
50
52
  }
51
53
  });
@@ -33,7 +33,7 @@ function process(stylesheets, styles, mediaAllInfo) {
33
33
  const stats = { processed: 0, discarded: 0 };
34
34
  let sheetIndex = 0;
35
35
  stylesheets.forEach((stylesheetInfo, key) => {
36
- if (!stylesheetInfo.scoped && !key.urlNode) {
36
+ if (!stylesheetInfo.scoped && stylesheetInfo.stylesheet && !key.urlNode) {
37
37
  const cssRules = stylesheetInfo.stylesheet.children;
38
38
  if (cssRules) {
39
39
  stats.processed += cssRules.size;
@@ -16953,7 +16953,9 @@ async function evalTemplate(template = "", options, content, doc, context = {})
16953
16953
  "bookmark-pathname-flat": { getter: () => bookmarkFolder, dontReplaceSlash: false },
16954
16954
  "profile-name": { getter: () => options.profileName },
16955
16955
  "filename-extension": { getter: () => getFilenameExtension(options) },
16956
- "save-action": { getter: () => options.selected ? "selection" : "page" }
16956
+ "save-action": { getter: () => options.selected ? "selection" : "page" },
16957
+ "options-json": { getter: () => JSON.stringify(getFilteredOptions(options)) },
16958
+ "options-text": { getter: () => optionsToText(getFilteredOptions(options)) }
16957
16959
  };
16958
16960
  if (content) {
16959
16961
  variables["digest-sha-256"] = { getter: async () => digest("SHA-256", content) };
@@ -17050,6 +17052,14 @@ async function evalTemplate(template = "", options, content, doc, context = {})
17050
17052
  options[name] = value;
17051
17053
  }
17052
17054
  }
17055
+ },
17056
+ "option-value": key => {
17057
+ const filteredValue = getFilteredOptions(options)[key];
17058
+ if (filteredValue === undefined || filteredValue === null) {
17059
+ return "";
17060
+ } else {
17061
+ return JSON.stringify(filteredValue);
17062
+ }
17053
17063
  }
17054
17064
  };
17055
17065
  functions["date-locale"].dontReplaceSlash = true;
@@ -17251,4 +17261,52 @@ function getFilenameExtension(options) {
17251
17261
  } else {
17252
17262
  return "html";
17253
17263
  }
17264
+ }
17265
+
17266
+ function getFilteredOptions(options) {
17267
+ const filteredOptions = Object.assign({}, options);
17268
+ delete filteredOptions.content;
17269
+ delete filteredOptions.usedFonts;
17270
+ delete filteredOptions.extensionScriptFiles;
17271
+ delete filteredOptions.taskId;
17272
+ delete filteredOptions.updatedResources;
17273
+ delete filteredOptions.visitDate;
17274
+ delete filteredOptions.keepFilename;
17275
+ delete filteredOptions.insertCanonicalLink;
17276
+ delete filteredOptions.frames;
17277
+ delete filteredOptions.win;
17278
+ delete filteredOptions.doc;
17279
+ delete filteredOptions.url;
17280
+ delete filteredOptions.resourceReferrer;
17281
+ delete filteredOptions.baseURI;
17282
+ delete filteredOptions.rootDocument;
17283
+ delete filteredOptions.fontTests;
17284
+ delete filteredOptions.canvases;
17285
+ delete filteredOptions.fonts;
17286
+ delete filteredOptions.worklets;
17287
+ delete filteredOptions.stylesheets;
17288
+ delete filteredOptions.images;
17289
+ delete filteredOptions.posters;
17290
+ delete filteredOptions.videos;
17291
+ delete filteredOptions.shadowRoots;
17292
+ delete filteredOptions.referrer;
17293
+ delete filteredOptions.adoptedStyleSheets;
17294
+ delete filteredOptions.tabId;
17295
+ delete filteredOptions.tabIndex;
17296
+ delete filteredOptions.saveDate;
17297
+ delete filteredOptions.saveUrl;
17298
+ delete filteredOptions.title;
17299
+ delete filteredOptions.info;
17300
+ return filteredOptions;
17301
+ }
17302
+
17303
+ function optionsToText(options) {
17304
+ const csv = [];
17305
+ for (const key in options) {
17306
+ const value = options[key];
17307
+ if (typeof value != "function" && value !== undefined && value !== null && value !== "") {
17308
+ csv.push(key + ": " + JSON.stringify(value));
17309
+ }
17310
+ }
17311
+ return csv.join("\n");
17254
17312
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "single-file-core",
3
- "version": "1.5.16",
3
+ "version": "1.5.18",
4
4
  "description": "SingleFile Core",
5
5
  "author": "Gildas Lormeau",
6
6
  "license": "AGPL-3.0-or-later",