Procházet zdrojové kódy

added missing guards to make CSS transform safer

Gildas před 7 roky
rodič
revize
bc4dc74034

+ 35 - 29
lib/single-file/css-fonts-alt-minifier.js

@@ -63,14 +63,16 @@ this.fontsAltMinifier = this.fontsAltMinifier || (() => {
 			let sheetIndex = 0;
 			stylesheets.forEach(stylesheetInfo => {
 				const cssRules = stylesheetInfo.stylesheet.children;
-				stats.rules.processed += cssRules.getSize();
-				stats.rules.discarded += cssRules.getSize();
-				if (stylesheetInfo.mediaText && stylesheetInfo.mediaText != MEDIA_ALL) {
-					const mediaFontsDetails = createFontsDetailsInfo();
-					fontsDetails.medias.set("media-" + sheetIndex + "-" + stylesheetInfo.mediaText, mediaFontsDetails);
-					getFontsDetails(doc, cssRules, sheetIndex, mediaFontsDetails);
-				} else {
-					getFontsDetails(doc, cssRules, sheetIndex, fontsDetails);
+				if (cssRules) {
+					stats.rules.processed += cssRules.getSize();
+					stats.rules.discarded += cssRules.getSize();
+					if (stylesheetInfo.mediaText && stylesheetInfo.mediaText != MEDIA_ALL) {
+						const mediaFontsDetails = createFontsDetailsInfo();
+						fontsDetails.medias.set("media-" + sheetIndex + "-" + stylesheetInfo.mediaText, mediaFontsDetails);
+						getFontsDetails(doc, cssRules, sheetIndex, mediaFontsDetails);
+					} else {
+						getFontsDetails(doc, cssRules, sheetIndex, fontsDetails);
+					}
 				}
 				sheetIndex++;
 			});
@@ -78,12 +80,15 @@ this.fontsAltMinifier = this.fontsAltMinifier || (() => {
 			sheetIndex = 0;
 			stylesheets.forEach(stylesheetInfo => {
 				const cssRules = stylesheetInfo.stylesheet.children;
-				if (stylesheetInfo.mediaText && stylesheetInfo.mediaText != MEDIA_ALL) {
-					processFontFaceRules(cssRules, sheetIndex, fontsDetails.medias.get("media-" + sheetIndex + "-" + stylesheetInfo.mediaText), stats);
-				} else {
-					processFontFaceRules(cssRules, sheetIndex, fontsDetails, stats);
+				const media = stylesheetInfo.mediaText;
+				if (cssRules) {
+					if (media && media != MEDIA_ALL) {
+						processFontFaceRules(cssRules, sheetIndex, fontsDetails.medias.get("media-" + sheetIndex + "-" + media), stats);
+					} else {
+						processFontFaceRules(cssRules, sheetIndex, fontsDetails, stats);
+					}
+					stats.rules.discarded -= cssRules.getSize();
 				}
-				stats.rules.discarded -= cssRules.getSize();
 				sheetIndex++;
 			});
 			return stats;
@@ -99,26 +104,24 @@ this.fontsAltMinifier = this.fontsAltMinifier || (() => {
 				mediaFontsDetails.medias.set("media-" + sheetIndex + "-" + mediaIndex + "-" + mediaText, fontsDetails);
 				mediaIndex++;
 				getFontsDetails(doc, cssRule.block.children, sheetIndex, fontsDetails);
-			} if (cssRule.type == "Atrule" && cssRule.name == "supports" && cssRule.block && cssRule.block.children && cssRule.prelude) {
+			} else if (cssRule.type == "Atrule" && cssRule.name == "supports" && cssRule.block && cssRule.block.children && cssRule.prelude) {
 				const supportsText = cssTree.generate(cssRule.prelude);
 				const fontsDetails = createFontsDetailsInfo();
 				mediaFontsDetails.supports.set("supports-" + sheetIndex + "-" + supportsIndex + "-" + supportsText, fontsDetails);
 				supportsIndex++;
 				getFontsDetails(doc, cssRule.block.children, sheetIndex, fontsDetails);
-			} else {
-				if (cssRule.type == "Atrule" && cssRule.name == "font-face") {
-					const fontKey = getFontKey(cssRule);
-					let fontInfo = mediaFontsDetails.fonts.get(fontKey);
-					if (!fontInfo) {
-						fontInfo = [];
-						mediaFontsDetails.fonts.set(fontKey, fontInfo);
-					}
-					const src = getPropertyValue(cssRule, "src");
-					if (src) {
-						const fontSources = src.match(REGEXP_URL_FUNCTION);
-						if (fontSources) {
-							fontSources.forEach(source => fontInfo.unshift(source));
-						}
+			} else if (cssRule.type == "Atrule" && cssRule.name == "font-face" && cssRule.block && cssRule.block.children) {
+				const fontKey = getFontKey(cssRule);
+				let fontInfo = mediaFontsDetails.fonts.get(fontKey);
+				if (!fontInfo) {
+					fontInfo = [];
+					mediaFontsDetails.fonts.set(fontKey, fontInfo);
+				}
+				const src = getPropertyValue(cssRule, "src");
+				if (src) {
+					const fontSources = src.match(REGEXP_URL_FUNCTION);
+					if (fontSources) {
+						fontSources.forEach(source => fontInfo.unshift(source));
 					}
 				}
 			}
@@ -222,7 +225,10 @@ this.fontsAltMinifier = this.fontsAltMinifier || (() => {
 	}
 
 	function getPropertyValue(cssRule, propertyName) {
-		const property = cssRule.block.children.filter(node => node.property == propertyName).tail;
+		let property;
+		if (cssRule.block.children) {
+			property = cssRule.block.children.filter(node => node.property == propertyName).tail;
+		}
 		if (property) {
 			try {
 				return cssTree.generate(property.data.value);

+ 16 - 9
lib/single-file/css-fonts-minifier.js

@@ -41,10 +41,12 @@ this.fontsMinifier = this.fontsMinifier || (() => {
 			let pseudoElementsContent = "";
 			stylesheets.forEach(stylesheetInfo => {
 				const cssRules = stylesheetInfo.stylesheet.children;
-				stats.processed += cssRules.getSize();
-				stats.discarded += cssRules.getSize();
-				getFontsInfo(cssRules, fontsInfo);
-				pseudoElementsContent += getPseudoElementsContent(doc, cssRules);
+				if (cssRules) {
+					stats.processed += cssRules.getSize();
+					stats.discarded += cssRules.getSize();
+					getFontsInfo(cssRules, fontsInfo);
+					pseudoElementsContent += getPseudoElementsContent(doc, cssRules);
+				}
 			});
 			styles.forEach(style => {
 				const fontFamilyNames = getFontFamilyNames(style);
@@ -69,8 +71,10 @@ this.fontsMinifier = this.fontsMinifier || (() => {
 			const docContent = doc.body.innerText + pseudoElementsContent;
 			stylesheets.forEach(stylesheetInfo => {
 				const cssRules = stylesheetInfo.stylesheet.children;
-				filterUnusedFonts(cssRules, fontsInfo.declared, unusedFonts, filteredUsedFonts, docContent);
-				stats.rules.discarded -= cssRules.getSize();
+				if (cssRules) {
+					filterUnusedFonts(cssRules, fontsInfo.declared, unusedFonts, filteredUsedFonts, docContent);
+					stats.rules.discarded -= cssRules.getSize();
+				}
 			});
 			return stats;
 		}
@@ -78,7 +82,7 @@ this.fontsMinifier = this.fontsMinifier || (() => {
 
 	function getFontsInfo(cssRules, fontsInfo) {
 		cssRules.forEach(cssRule => {
-			if (cssRule.type == "Atrule" && cssRule.name == "media" && cssRule.block) {
+			if (cssRule.type == "Atrule" && cssRule.name == "media" && cssRule.block && cssRule.block.children) {
 				getFontsInfo(cssRule.block.children, fontsInfo);
 			} else if (cssRule.type == "Rule") {
 				const fontFamilyNames = getFontFamilyNames(cssRule.block);
@@ -103,7 +107,7 @@ this.fontsMinifier = this.fontsMinifier || (() => {
 		const removedRules = [];
 		for (let cssRule = cssRules.head; cssRule; cssRule = cssRule.next) {
 			const ruleData = cssRule.data;
-			if (ruleData.type == "Atrule" && ruleData.name == "media" && ruleData.block) {
+			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"));
@@ -138,7 +142,10 @@ this.fontsMinifier = this.fontsMinifier || (() => {
 	}
 
 	function getPropertyValue(cssRule, propertyName) {
-		const property = cssRule.block.children.filter(node => node.property == propertyName).tail;
+		let property;
+		if (cssRule.block.children) {
+			property = cssRule.block.children.filter(node => node.property == propertyName).tail;
+		}
 		if (property) {
 			try {
 				return cssTree.generate(property.data.value);

+ 9 - 6
lib/single-file/css-matched-rules.js

@@ -36,12 +36,15 @@ this.matchedRules = this.matchedRules || (() => {
 			const styleElement = doc.createElement("style");
 			doc.body.appendChild(styleElement);
 			docStyle.stylesheets.forEach(stylesheetInfo => {
-				if (stylesheetInfo.mediaText && stylesheetInfo.mediaText != MEDIA_ALL) {
-					const mediaInfo = createMediaInfo(stylesheetInfo.mediaText);
-					this.mediaAllInfo.medias.set("style-" + sheetIndex + "-" + stylesheetInfo.mediaText, mediaInfo);
-					getMatchedElementsRules(doc, stylesheetInfo.stylesheet.children, mediaInfo, sheetIndex, docStyle, matchedElementsCache, styleElement.sheet);
-				} else {
-					getMatchedElementsRules(doc, stylesheetInfo.stylesheet.children, this.mediaAllInfo, sheetIndex, docStyle, matchedElementsCache, styleElement.sheet);
+				const cssRules = stylesheetInfo.stylesheet.children;
+				if (cssRules) {
+					if (stylesheetInfo.mediaText && stylesheetInfo.mediaText != MEDIA_ALL) {
+						const mediaInfo = createMediaInfo(stylesheetInfo.mediaText);
+						this.mediaAllInfo.medias.set("style-" + sheetIndex + "-" + stylesheetInfo.mediaText, mediaInfo);
+						getMatchedElementsRules(doc, cssRules, mediaInfo, sheetIndex, docStyle, matchedElementsCache, styleElement.sheet);
+					} else {
+						getMatchedElementsRules(doc, cssRules, this.mediaAllInfo, sheetIndex, docStyle, matchedElementsCache, styleElement.sheet);
+					}
 				}
 				sheetIndex++;
 			});

+ 3 - 3
lib/single-file/css-medias-minifier.js

@@ -25,9 +25,9 @@ this.mediasMinifier = this.mediasMinifier || (() => {
 	return {
 		process: stylesheets => {
 			const stats = { processed: 0, discarded: 0 };
-			stylesheets.forEach((stylesheet, element) => {
-				if (matchesMediaType(stylesheet.mediaText || "all", "screen")) {
-					const removedRules = processRules(stylesheet.stylesheet.children, stats);
+			stylesheets.forEach((stylesheetInfo, element) => {
+				if (matchesMediaType(stylesheetInfo.mediaText || "all", "screen") && stylesheetInfo.stylesheet.children) {
+					const removedRules = processRules(stylesheetInfo.stylesheet.children, stats);
 					removedRules.forEach(({ cssRules, cssRule }) => cssRules.remove(cssRule));
 				} else {
 					stylesheets.delete(element);

+ 9 - 7
lib/single-file/css-rules-minifier.js

@@ -36,11 +36,13 @@ this.cssRulesMinifier = this.cssRulesMinifier || (() => {
 					mediaInfo = mediaAllInfo;
 				}
 				const cssRules = stylesheetInfo.stylesheet.children;
-				stats.processed += cssRules.getSize();
-				stats.discarded += cssRules.getSize();
-				processRules(cssRules, sheetIndex, mediaInfo);
+				if (cssRules) {
+					stats.processed += cssRules.getSize();
+					stats.discarded += cssRules.getSize();
+					processRules(cssRules, sheetIndex, mediaInfo);
+					stats.discarded -= cssRules.getSize();
+				}
 				sheetIndex++;
-				stats.discarded -= stylesheetInfo.stylesheet.children.getSize();
 			});
 			let startTime;
 			if (DEBUG) {
@@ -57,9 +59,9 @@ this.cssRulesMinifier = this.cssRulesMinifier || (() => {
 
 	function processRules(cssRules, sheetIndex, mediaInfo) {
 		let mediaRuleIndex = 0, startTime;
-		if (DEBUG && cssRules.length > 1) {
+		if (DEBUG && cssRules.getSize() > 1) {
 			startTime = Date.now();
-			log("  -- STARTED processRules", "rules.length =", cssRules.children.toArray().length);
+			log("  -- STARTED processRules", "rules.length =", cssRules.getSize());
 		}
 		const removedCssRules = [];
 		for (let cssRule = cssRules.head; cssRule; cssRule = cssRule.next) {
@@ -87,7 +89,7 @@ this.cssRulesMinifier = this.cssRulesMinifier || (() => {
 			}
 		}
 		removedCssRules.forEach(cssRule => cssRules.remove(cssRule));
-		if (DEBUG && cssRules.length > 1) {
+		if (DEBUG && cssRules.getSize() > 1) {
 			log("  -- ENDED   processRules delay =", Date.now() - startTime);
 		}
 	}

+ 16 - 9
lib/single-file/single-file-core.js

@@ -778,17 +778,24 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 						} else {
 							stylesheetContent = await DomProcessorHelper.resolveImportURLs(element.textContent, this.baseURI, options);
 						}
-						const stylesheet = cssTree.parse(stylesheetContent);
-						if (this.options.compressCSS) {
-							const removedRules = [];
-							for (let cssRule = stylesheet.children.head; cssRule; cssRule = cssRule.next) {
-								if (cssRule.data.type == "Raw" && cssRule.data.value && cssRule.data.value.trim().startsWith("//")) {
-									removedRules.push(cssRule);
+						let stylesheet;
+						try {
+							stylesheet = cssTree.parse(stylesheetContent);
+						} catch (error) {
+							// ignored
+						}
+						if (stylesheet && stylesheet.children) {
+							if (this.options.compressCSS) {
+								const removedRules = [];
+								for (let cssRule = stylesheet.children.head; cssRule; cssRule = cssRule.next) {
+									if (cssRule.data.type == "Raw" && cssRule.data.value && cssRule.data.value.trim().startsWith("//")) {
+										removedRules.push(cssRule);
+									}
 								}
+								removedRules.forEach(cssRule => stylesheet.children.remove(cssRule));
 							}
-							removedRules.forEach(cssRule => stylesheet.children.remove(cssRule));
+							this.stylesheets.get(element).stylesheet = stylesheet;
 						}
-						this.stylesheets.get(element).stylesheet = stylesheet;
 					}
 				}));
 		}
@@ -1512,7 +1519,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		}
 
 		static testIgnoredPath(resourceURL) {
-			return resourceURL && (resourceURL.startsWith(DATA_URI_PREFIX) /*|| resourceURL.startsWith(BLOB_URI_PREFIX)*/ || resourceURL == ABOUT_BLANK_URI);
+			return resourceURL && (resourceURL.startsWith(DATA_URI_PREFIX) || resourceURL == ABOUT_BLANK_URI);
 		}
 
 		static testValidPath(resourceURL, baseURI, docURL) {