Selaa lähdekoodia

take into account 'quotes" css property when searching for generated content

Gildas 7 vuotta sitten
vanhempi
sitoutus
060f8b387d
1 muutettua tiedostoa jossa 50 lisäystä ja 46 poistoa
  1. 50 46
      lib/single-file/modules/css-fonts-minifier.js

+ 50 - 46
lib/single-file/modules/css-fonts-minifier.js

@@ -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) {