|
|
@@ -28,7 +28,6 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
const REGEXP_STARTS_U_PLUS = /^U\+/i;
|
|
|
const REGEXP_SIMPLE_QUOTES_STRING = /^'(.*?)'$/;
|
|
|
const REGEXP_DOUBLE_QUOTES_STRING = /^"(.*?)"$/;
|
|
|
- const PSEUDO_ELEMENTS = ["::after", "::before", "::first-line", "::first-letter", ":before", ":after", ":first-line", ":first-letter", "::placeholder", "::selection", "::marker", "::cue", "::slotted", "::spelling-error", "::grammar-error"];
|
|
|
const FONT_WEIGHTS = {
|
|
|
normal: "400",
|
|
|
bold: "700"
|
|
|
@@ -38,22 +37,27 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
process: (doc, stylesheets, styles, options) => {
|
|
|
const stats = { rules: { processed: 0, discarded: 0 }, fonts: { processed: 0, discarded: 0 } };
|
|
|
const fontsInfo = { declared: [], used: [] };
|
|
|
- let pseudoElementsContent = "";
|
|
|
+ const workStyleElement = doc.createElement("style");
|
|
|
+ let docContent = "";
|
|
|
+ doc.body.appendChild(workStyleElement);
|
|
|
stylesheets.forEach(stylesheetInfo => {
|
|
|
const cssRules = stylesheetInfo.stylesheet.children;
|
|
|
if (cssRules) {
|
|
|
stats.processed += cssRules.getSize();
|
|
|
stats.discarded += cssRules.getSize();
|
|
|
getFontsInfo(cssRules, fontsInfo);
|
|
|
- pseudoElementsContent += getPseudoElementsContent(doc, cssRules);
|
|
|
+ docContent = getRulesTextContent(doc, cssRules, workStyleElement.sheet, docContent);
|
|
|
}
|
|
|
});
|
|
|
- styles.forEach(style => {
|
|
|
- const fontFamilyNames = getFontFamilyNames(style);
|
|
|
+ styles.forEach(declarations => {
|
|
|
+ const fontFamilyNames = getFontFamilyNames(declarations);
|
|
|
if (fontFamilyNames.length) {
|
|
|
fontsInfo.used.push(fontFamilyNames);
|
|
|
}
|
|
|
+ docContent = getDeclarationsTextContent(declarations.children, workStyleElement.sheet, docContent);
|
|
|
});
|
|
|
+ workStyleElement.remove();
|
|
|
+ docContent += doc.body.innerText;
|
|
|
const variableFound = fontsInfo.used.find(fontNames => fontNames.find(fontName => fontName.startsWith("var(--")));
|
|
|
let unusedFonts, filteredUsedFonts;
|
|
|
if (variableFound) {
|
|
|
@@ -68,7 +72,6 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
}));
|
|
|
unusedFonts = fontsInfo.declared.filter(fontInfo => !filteredUsedFonts.has(fontInfo.fontFamily));
|
|
|
}
|
|
|
- const docContent = doc.body.innerText + pseudoElementsContent;
|
|
|
stylesheets.forEach(stylesheetInfo => {
|
|
|
const cssRules = stylesheetInfo.stylesheet.children;
|
|
|
if (cssRules) {
|
|
|
@@ -91,11 +94,11 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
}
|
|
|
} else {
|
|
|
if (ruleData.type == "Atrule" && ruleData.name == "font-face") {
|
|
|
- const fontFamily = getFontFamily(getPropertyValue(ruleData, "font-family"));
|
|
|
+ const fontFamily = getFontFamily(getDeclarationValue(ruleData.block.children, "font-family"));
|
|
|
if (fontFamily) {
|
|
|
- const fontWeight = getFontWeight(getPropertyValue(ruleData, "font-weight") || "400");
|
|
|
- const fontStyle = getPropertyValue(ruleData, "font-style") || "normal";
|
|
|
- const fontVariant = getPropertyValue(ruleData, "font-variant") || "normal";
|
|
|
+ const fontWeight = getFontWeight(getDeclarationValue(ruleData.block.children, "font-weight") || "400");
|
|
|
+ const fontStyle = getDeclarationValue(ruleData.block.children, "font-style") || "normal";
|
|
|
+ const fontVariant = getDeclarationValue(ruleData.block.children, "font-variant") || "normal";
|
|
|
fontsInfo.declared.push({ fontFamily, fontWeight, fontStyle, fontVariant });
|
|
|
}
|
|
|
}
|
|
|
@@ -110,9 +113,9 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
if (ruleData.type == "Atrule" && ruleData.name == "media" && ruleData.block && ruleData.block.children) {
|
|
|
filterUnusedFonts(ruleData.block.children, declaredFonts, unusedFonts, filteredUsedFonts, docContent);
|
|
|
} else if (ruleData.type == "Atrule" && ruleData.name == "font-face") {
|
|
|
- const fontFamily = getFontFamily(getPropertyValue(ruleData, "font-family"));
|
|
|
+ const fontFamily = getFontFamily(getDeclarationValue(ruleData.block.children, "font-family"));
|
|
|
if (fontFamily) {
|
|
|
- const unicodeRange = getPropertyValue(ruleData, "unicode-range");
|
|
|
+ const unicodeRange = getDeclarationValue(ruleData.block.children, "unicode-range");
|
|
|
if (unusedFonts.find(fontInfo => fontInfo.fontFamily == fontFamily) || !testUnicodeRange(docContent, unicodeRange) || !testUsedFont(ruleData, fontFamily, declaredFonts, filteredUsedFonts)) {
|
|
|
removedRules.push(cssRule);
|
|
|
}
|
|
|
@@ -135,9 +138,9 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
let test;
|
|
|
const optionalUsedFonts = filteredUsedFonts && filteredUsedFonts.get(familyName);
|
|
|
if (optionalUsedFonts && optionalUsedFonts.length) {
|
|
|
- const fontStyle = getPropertyValue(ruleData, "font-style") || "normal";
|
|
|
- const fontWeight = getFontWeight(getPropertyValue(ruleData, "font-weight") || "400");
|
|
|
- const fontVariant = getPropertyValue(ruleData, "font-variant") || "normal";
|
|
|
+ const fontStyle = getDeclarationValue(ruleData.block.children, "font-style") || "normal";
|
|
|
+ const fontWeight = getFontWeight(getDeclarationValue(ruleData.block.children, "font-weight") || "400");
|
|
|
+ const fontVariant = getDeclarationValue(ruleData.block.children, "font-variant") || "normal";
|
|
|
const declaredFontsWeights = declaredFonts
|
|
|
.filter(fontInfo => fontInfo.fontFamily == familyName && fontInfo.fontStyle == fontStyle && testFontVariant(fontInfo, fontVariant))
|
|
|
.map(fontInfo => fontInfo.fontWeight)
|
|
|
@@ -150,10 +153,10 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
return test;
|
|
|
}
|
|
|
|
|
|
- function getPropertyValue(ruleData, propertyName) {
|
|
|
+ function getDeclarationValue(declarations, propertyName) {
|
|
|
let property;
|
|
|
- if (ruleData.block.children) {
|
|
|
- property = ruleData.block.children.filter(node => node.property == propertyName).tail;
|
|
|
+ if (declarations) {
|
|
|
+ property = declarations.filter(declaration => declaration.property == propertyName).tail;
|
|
|
}
|
|
|
if (property) {
|
|
|
try {
|
|
|
@@ -231,27 +234,40 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
return fontWeights.find(weight => weight > fontWeight);
|
|
|
}
|
|
|
|
|
|
- function getPseudoElementsContent(doc, cssRules) {
|
|
|
- return cssRules.toArray().map(ruleData => {
|
|
|
+ function getRulesTextContent(doc, cssRules, workStylesheet, content) {
|
|
|
+ cssRules.forEach(ruleData => {
|
|
|
if (ruleData.block && ruleData.block.children && ruleData.prelude && ruleData.prelude.children) {
|
|
|
if (ruleData.type == "Atrule" && ruleData.name == "media") {
|
|
|
- return getPseudoElementsContent(doc, ruleData.block.children);
|
|
|
+ content = getRulesTextContent(doc, ruleData.block.children, workStylesheet, content);
|
|
|
} else if (ruleData.type == "Rule") {
|
|
|
- const selector = cssTree.generate(ruleData.prelude); // TODO use OM
|
|
|
- if (testPseudoElements(selector)) {
|
|
|
- const value = docHelper.removeQuotes(getPropertyValue(ruleData, "content") || "");
|
|
|
- if (value) {
|
|
|
- const styleElement = doc.createElement("style");
|
|
|
- styleElement.textContent = "tmp { content:\"" + value + "\"}";
|
|
|
- doc.documentElement.appendChild(styleElement);
|
|
|
- let content = docHelper.removeQuotes(styleElement.sheet.cssRules[0].style.getPropertyValue("content"));
|
|
|
- styleElement.remove();
|
|
|
- return content;
|
|
|
- }
|
|
|
- }
|
|
|
+ content = getDeclarationsTextContent(ruleData.block.children, workStylesheet, content);
|
|
|
}
|
|
|
}
|
|
|
- }).join("");
|
|
|
+ });
|
|
|
+ return content;
|
|
|
+ }
|
|
|
+
|
|
|
+ function getDeclarationsTextContent(declarations, workStylesheet, content) {
|
|
|
+ const contentText = getDeclarationUnescapedValue(declarations, "content", workStylesheet);
|
|
|
+ const quotesText = getDeclarationUnescapedValue(declarations, "quotes", workStylesheet);
|
|
|
+ if (!content.includes(contentText)) {
|
|
|
+ content += contentText;
|
|
|
+ }
|
|
|
+ if (!content.includes(quotesText)) {
|
|
|
+ content += quotesText;
|
|
|
+ }
|
|
|
+ return content;
|
|
|
+ }
|
|
|
+
|
|
|
+ function getDeclarationUnescapedValue(declarations, property, workStylesheet) {
|
|
|
+ const rawValue = docHelper.removeQuotes(getDeclarationValue(declarations, property) || "");
|
|
|
+ if (rawValue) {
|
|
|
+ workStylesheet.insertRule("tmp { content:\"" + rawValue + "\"}");
|
|
|
+ const value = docHelper.removeQuotes(workStylesheet.cssRules[0].style.getPropertyValue("content"));
|
|
|
+ workStylesheet.deleteRule(0);
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+ return "";
|
|
|
}
|
|
|
|
|
|
function testFontVariant(fontInfo, fontVariant) {
|
|
|
@@ -294,18 +310,6 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- function testPseudoElements(selectorText) {
|
|
|
- let indexSelector = 0, found;
|
|
|
- selectorText = selectorText.toLowerCase();
|
|
|
- while (indexSelector < PSEUDO_ELEMENTS.length && !found) {
|
|
|
- found = selectorText.includes(PSEUDO_ELEMENTS[indexSelector]);
|
|
|
- if (!found) {
|
|
|
- indexSelector++;
|
|
|
- }
|
|
|
- }
|
|
|
- return found;
|
|
|
- }
|
|
|
-
|
|
|
function transformRange(range) {
|
|
|
range = range.replace(REGEXP_STARTS_U_PLUS, "");
|
|
|
while (range.length < 6) {
|