single-file-core 1.6.19 → 1.6.21
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 +67 -2
- package/core/index.js +3 -2
- package/core/lib/processor-helper-common.js +17 -24
- package/core/lib/processor-helper-inline.js +7 -1
- package/core/lib/processor-helper.js +2 -1
- package/modules/css-fonts-minifier.js +257 -129
- package/package.json +1 -1
- package/vendor/css-font-property-parser.js +47 -6
- package/vendor/css-tree.js +12 -11
- package/vendor/zip/z-worker.js +1 -1
- package/vendor/zip/zip.js +867 -477
- package/vendor/zip/zip.min.js +1 -1
package/core/helper.js
CHANGED
|
@@ -86,6 +86,17 @@ const FONT_WEIGHTS = {
|
|
|
86
86
|
bolder: "700",
|
|
87
87
|
lighter: "100"
|
|
88
88
|
};
|
|
89
|
+
const FONT_STRETCHES = {
|
|
90
|
+
"ultra-condensed": "50%",
|
|
91
|
+
"extra-condensed": "62.5%",
|
|
92
|
+
"condensed": "75%",
|
|
93
|
+
"semi-condensed": "87.5%",
|
|
94
|
+
"normal": "100%",
|
|
95
|
+
"semi-expanded": "112.5%",
|
|
96
|
+
"expanded": "125%",
|
|
97
|
+
"extra-expanded": "150%",
|
|
98
|
+
"ultra-expanded": "200%"
|
|
99
|
+
};
|
|
89
100
|
const COMMENT_HEADER_LEGACY = "Archive processed by SingleFile";
|
|
90
101
|
const ELEMENT_NODE_TYPE = 1;
|
|
91
102
|
const TEXT_NODE_TYPE = 3;
|
|
@@ -139,6 +150,8 @@ export {
|
|
|
139
150
|
removeQuotes,
|
|
140
151
|
flatten,
|
|
141
152
|
getFontWeight,
|
|
153
|
+
getFontStretch,
|
|
154
|
+
getStylesheetsInCascadeOrder,
|
|
142
155
|
normalizeFontFamily,
|
|
143
156
|
getShadowRoot,
|
|
144
157
|
appendInfobar,
|
|
@@ -926,8 +939,9 @@ function getUsedFont(computedStyle, usedFonts, usedFontsCharacters, drawnCharact
|
|
|
926
939
|
if (fontFamilyName) {
|
|
927
940
|
const fontWeight = getFontWeight(computedStyle.getPropertyValue("font-weight"));
|
|
928
941
|
const fontVariant = computedStyle.getPropertyValue("font-variant") || "normal";
|
|
929
|
-
const
|
|
930
|
-
|
|
942
|
+
const fontStretch = getFontStretch(computedStyle.getPropertyValue("font-stretch") || "normal");
|
|
943
|
+
const value = [fontFamilyName, fontWeight, fontStyle, fontVariant, fontStretch];
|
|
944
|
+
usedFonts.set(JSON.stringify(value), value);
|
|
931
945
|
if (usedFontsCharacters && drawnCharacters) {
|
|
932
946
|
addUsedFontCharacters(usedFontsCharacters, fontFamilyName, fontStyle, drawnCharacters);
|
|
933
947
|
}
|
|
@@ -1246,6 +1260,57 @@ function getFontWeight(weight) {
|
|
|
1246
1260
|
return FONT_WEIGHTS[weight.toLowerCase().trim()] || weight;
|
|
1247
1261
|
}
|
|
1248
1262
|
|
|
1263
|
+
function getFontStretch(stretch) {
|
|
1264
|
+
return FONT_STRETCHES[stretch] || stretch;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
function getStylesheetsInCascadeOrder(stylesheets) {
|
|
1268
|
+
const entries = [];
|
|
1269
|
+
const entriesByRules = new Map();
|
|
1270
|
+
stylesheets.forEach((stylesheetInfo, key) => {
|
|
1271
|
+
const entry = { stylesheetInfo, key, index: entries.length };
|
|
1272
|
+
entries.push(entry);
|
|
1273
|
+
if (stylesheetInfo.stylesheet && stylesheetInfo.stylesheet.children) {
|
|
1274
|
+
entriesByRules.set(stylesheetInfo.stylesheet.children, entry);
|
|
1275
|
+
}
|
|
1276
|
+
});
|
|
1277
|
+
const importedEntries = new Set();
|
|
1278
|
+
entries.forEach(entry => getImportedStylesheetEntries(entry, entriesByRules).forEach(importedEntry => importedEntries.add(importedEntry)));
|
|
1279
|
+
const orderedEntries = [];
|
|
1280
|
+
const visitedEntries = new Set();
|
|
1281
|
+
entries
|
|
1282
|
+
.filter(entry => !importedEntries.has(entry))
|
|
1283
|
+
.forEach(entry => addStylesheetEntry(entry, entriesByRules, orderedEntries, visitedEntries));
|
|
1284
|
+
entries
|
|
1285
|
+
.filter(entry => !visitedEntries.has(entry))
|
|
1286
|
+
.forEach(entry => addStylesheetEntry(entry, entriesByRules, orderedEntries, visitedEntries));
|
|
1287
|
+
return orderedEntries;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
function addStylesheetEntry(entry, entriesByRules, orderedEntries, visitedEntries) {
|
|
1291
|
+
if (!visitedEntries.has(entry)) {
|
|
1292
|
+
visitedEntries.add(entry);
|
|
1293
|
+
getImportedStylesheetEntries(entry, entriesByRules).forEach(importedEntry => addStylesheetEntry(importedEntry, entriesByRules, orderedEntries, visitedEntries));
|
|
1294
|
+
orderedEntries.push(entry);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
function getImportedStylesheetEntries(entry, entriesByRules) {
|
|
1299
|
+
const importedEntries = [];
|
|
1300
|
+
const stylesheet = entry.stylesheetInfo.stylesheet;
|
|
1301
|
+
if (stylesheet && stylesheet.children) {
|
|
1302
|
+
stylesheet.children.forEach(ruleData => {
|
|
1303
|
+
if (ruleData.type == "Atrule" && ruleData.name == "import" && ruleData.prelude && ruleData.prelude.children && ruleData.prelude.children.head) {
|
|
1304
|
+
const importedEntry = entriesByRules.get(ruleData.prelude.children.head.data.importedChildren);
|
|
1305
|
+
if (importedEntry) {
|
|
1306
|
+
importedEntries.push(importedEntry);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1311
|
+
return importedEntries;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1249
1314
|
function getContentSize(content) {
|
|
1250
1315
|
return new Blob([content]).size;
|
|
1251
1316
|
}
|
package/core/index.js
CHANGED
|
@@ -1343,10 +1343,11 @@ class Processor {
|
|
|
1343
1343
|
if (element.media) {
|
|
1344
1344
|
mediaText = element.media.toLowerCase();
|
|
1345
1345
|
}
|
|
1346
|
-
const
|
|
1346
|
+
const scope = element.closest("[" + SHADOWROOT_ATTRIBUTE_NAME + "]");
|
|
1347
1347
|
const stylesheetInfo = {
|
|
1348
1348
|
mediaText,
|
|
1349
|
-
scoped
|
|
1349
|
+
scoped: Boolean(scope),
|
|
1350
|
+
scope
|
|
1350
1351
|
};
|
|
1351
1352
|
await this.processorHelper.resolveStylesheets(element, stylesheetInfo, this.stylesheets, this.baseURI, options, this.workStyleElement, this.resources);
|
|
1352
1353
|
}));
|
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
import {
|
|
25
25
|
normalizeFontFamily,
|
|
26
26
|
getFontWeight,
|
|
27
|
+
getFontStretch,
|
|
28
|
+
getStylesheetsInCascadeOrder,
|
|
27
29
|
getDataURI
|
|
28
30
|
} from "./../helper.js";
|
|
29
31
|
import { serialize as serializeSrcset } from "./../../vendor/html-srcset-parser.js";
|
|
@@ -51,17 +53,6 @@ const REGEXP_FONT_FORMAT = /\.([^.?#]+)((\?|#).*?)?$/;
|
|
|
51
53
|
const REGEXP_FONT_FORMAT_VALUE = /format\((.*?)\)\s*,?$/;
|
|
52
54
|
const REGEXP_FONT_SRC = /(.*?)\s*,?$/;
|
|
53
55
|
const MEDIA_ALL = "all";
|
|
54
|
-
const FONT_STRETCHES = {
|
|
55
|
-
"ultra-condensed": "50%",
|
|
56
|
-
"extra-condensed": "62.5%",
|
|
57
|
-
"condensed": "75%",
|
|
58
|
-
"semi-condensed": "87.5%",
|
|
59
|
-
"normal": "100%",
|
|
60
|
-
"semi-expanded": "112.5%",
|
|
61
|
-
"expanded": "125%",
|
|
62
|
-
"extra-expanded": "150%",
|
|
63
|
-
"ultra-expanded": "200%"
|
|
64
|
-
};
|
|
65
56
|
const Blob = globalThis.Blob;
|
|
66
57
|
const Image = globalThis.Image;
|
|
67
58
|
const OffscreenCanvas = globalThis.OffscreenCanvas;
|
|
@@ -423,9 +414,12 @@ class ProcessorHelperCommon {
|
|
|
423
414
|
async removeAlternativeFonts(doc, stylesheets, fonts, fontTests) {
|
|
424
415
|
const fontsDetails = this.createFontsDetailsInfo();
|
|
425
416
|
const stats = { rules: { processed: 0, discarded: 0 }, fonts: { processed: 0, discarded: 0 } };
|
|
426
|
-
|
|
427
|
-
stylesheets.forEach(stylesheetInfo => {
|
|
417
|
+
const ruleScopes = new Map();
|
|
418
|
+
getStylesheetsInCascadeOrder(stylesheets).forEach(({ stylesheetInfo, index: sheetIndex }) => {
|
|
428
419
|
if (stylesheetInfo.stylesheet) {
|
|
420
|
+
if (stylesheetInfo.scope) {
|
|
421
|
+
cssTree.walk(stylesheetInfo.stylesheet, { visit: "Atrule", enter: node => ruleScopes.set(node, stylesheetInfo.scope) });
|
|
422
|
+
}
|
|
429
423
|
const cssRules = stylesheetInfo.stylesheet.children;
|
|
430
424
|
if (cssRules) {
|
|
431
425
|
stats.rules.processed += cssRules.size;
|
|
@@ -439,10 +433,9 @@ class ProcessorHelperCommon {
|
|
|
439
433
|
}
|
|
440
434
|
}
|
|
441
435
|
}
|
|
442
|
-
sheetIndex++;
|
|
443
436
|
});
|
|
444
437
|
processFontDetails(fontsDetails, fonts);
|
|
445
|
-
this.markRepeatedFontFaceRules(fontsDetails);
|
|
438
|
+
this.markRepeatedFontFaceRules(fontsDetails, ruleScopes, new Map());
|
|
446
439
|
await Promise.all([...stylesheets].map(async ([, stylesheetInfo], sheetIndex) => {
|
|
447
440
|
if (stylesheetInfo.stylesheet) {
|
|
448
441
|
const cssRules = stylesheetInfo.stylesheet.children;
|
|
@@ -460,19 +453,23 @@ class ProcessorHelperCommon {
|
|
|
460
453
|
return stats;
|
|
461
454
|
}
|
|
462
455
|
|
|
463
|
-
markRepeatedFontFaceRules(fontsDetails) {
|
|
456
|
+
markRepeatedFontFaceRules(fontsDetails, ruleScopes, scopeIds) {
|
|
464
457
|
const lastRules = new Map();
|
|
465
458
|
fontsDetails.fonts.forEach((fontInfo, ruleData) => {
|
|
466
|
-
const
|
|
459
|
+
const scope = ruleScopes.get(ruleData);
|
|
460
|
+
if (scope && !scopeIds.has(scope)) {
|
|
461
|
+
scopeIds.set(scope, scopeIds.size + 1);
|
|
462
|
+
}
|
|
463
|
+
const ruleKey = (scope ? scopeIds.get(scope) : 0) + " " + this.getFontKey(ruleData) + " " + this.getPropertyValue(ruleData, "src");
|
|
467
464
|
const previousRuleData = lastRules.get(ruleKey);
|
|
468
465
|
if (previousRuleData) {
|
|
469
466
|
fontsDetails.repeatedFonts.add(previousRuleData);
|
|
470
467
|
}
|
|
471
468
|
lastRules.set(ruleKey, ruleData);
|
|
472
469
|
});
|
|
473
|
-
fontsDetails.medias.forEach(mediaFontsDetails => this.markRepeatedFontFaceRules(mediaFontsDetails));
|
|
474
|
-
fontsDetails.supports.forEach(supportsFontsDetails => this.markRepeatedFontFaceRules(supportsFontsDetails));
|
|
475
|
-
fontsDetails.layers.forEach(layerFontsDetails => this.markRepeatedFontFaceRules(layerFontsDetails));
|
|
470
|
+
fontsDetails.medias.forEach(mediaFontsDetails => this.markRepeatedFontFaceRules(mediaFontsDetails, ruleScopes, scopeIds));
|
|
471
|
+
fontsDetails.supports.forEach(supportsFontsDetails => this.markRepeatedFontFaceRules(supportsFontsDetails, ruleScopes, scopeIds));
|
|
472
|
+
fontsDetails.layers.forEach(layerFontsDetails => this.markRepeatedFontFaceRules(layerFontsDetails, ruleScopes, scopeIds));
|
|
476
473
|
}
|
|
477
474
|
|
|
478
475
|
async processFontFaceRules(cssRules, sheetIndex, fontsDetails, fonts, fontTests, stats) {
|
|
@@ -739,10 +736,6 @@ function getURL(urlFunction) {
|
|
|
739
736
|
return urlMatch && urlMatch[1];
|
|
740
737
|
}
|
|
741
738
|
|
|
742
|
-
function getFontStretch(stretch) {
|
|
743
|
-
return FONT_STRETCHES[stretch] || stretch;
|
|
744
|
-
}
|
|
745
|
-
|
|
746
739
|
async function resizeImage(doc, dataURI, { imageReductionFactor, imageQuality }, element) {
|
|
747
740
|
if (dataURI) {
|
|
748
741
|
const contentType = dataURI.substring(5, dataURI.indexOf(";"));
|
|
@@ -582,9 +582,15 @@ function getProcessorHelperClass(utilInstance) {
|
|
|
582
582
|
groupDuplicateFonts(stylesheets, fonts, options) {
|
|
583
583
|
if (options.usedFonts && options.usedFonts.length) {
|
|
584
584
|
const fontFaces = [];
|
|
585
|
+
const scopeIds = new Map();
|
|
585
586
|
stylesheets.forEach(stylesheetInfo => {
|
|
586
587
|
if (stylesheetInfo.stylesheet && stylesheetInfo.stylesheet.children) {
|
|
587
|
-
|
|
588
|
+
const scope = stylesheetInfo.scope || null;
|
|
589
|
+
if (!scopeIds.has(scope)) {
|
|
590
|
+
scopeIds.set(scope, scopeIds.size);
|
|
591
|
+
}
|
|
592
|
+
const mediaScope = stylesheetInfo.mediaText ? "|media " + stylesheetInfo.mediaText : "";
|
|
593
|
+
getFontFaces(stylesheetInfo.stylesheet.children, scopeIds.get(scope) + mediaScope, fontFaces);
|
|
588
594
|
}
|
|
589
595
|
});
|
|
590
596
|
const families = new Map();
|
|
@@ -216,7 +216,7 @@ function getProcessorHelperClass(utilInstance) {
|
|
|
216
216
|
|
|
217
217
|
async resolveImportURLs(stylesheetInfo, baseURI, options, workStylesheet, resources, stylesheets, importedStyleSheets = new Set(), stylesheetReferrer) {
|
|
218
218
|
const stylesheet = stylesheetInfo.stylesheet;
|
|
219
|
-
const scoped = stylesheetInfo
|
|
219
|
+
const { scoped, scope } = stylesheetInfo;
|
|
220
220
|
this.resolveStylesheetURLs(stylesheet, baseURI, workStylesheet, stylesheetReferrer, options.stylesheetReferrers);
|
|
221
221
|
const imports = getImportFunctions(stylesheet);
|
|
222
222
|
await Promise.all(imports.map(async node => {
|
|
@@ -247,6 +247,7 @@ function getProcessorHelperClass(utilInstance) {
|
|
|
247
247
|
}
|
|
248
248
|
const stylesheetInfo = {
|
|
249
249
|
scoped,
|
|
250
|
+
scope,
|
|
250
251
|
mediaText,
|
|
251
252
|
layerName,
|
|
252
253
|
supportsCondition
|