From 9503c17bdfb45bb157df4393278403a93272276a Mon Sep 17 00:00:00 2001 From: Cyril Mizzi Date: Mon, 26 Feb 2018 17:31:09 +0100 Subject: [PATCH 1/6] adds keepChildren ability from whitelistPatterns Object[] --- __tests__/purgecssDefault.test.js | 42 +++++++++++++++++++++ lib/purgecss.es.js | 2 +- lib/purgecss.js | 2 +- src/index.js | 62 +++++++++++++++++++++++++++---- 4 files changed, 98 insertions(+), 10 deletions(-) diff --git a/__tests__/purgecssDefault.test.js b/__tests__/purgecssDefault.test.js index 76bc448c..09cd8110 100644 --- a/__tests__/purgecssDefault.test.js +++ b/__tests__/purgecssDefault.test.js @@ -335,3 +335,45 @@ describe('purge methods with raw content and default extractor', () => { expect(purgecssResult.includes('double-class')).toBe(true) }) }) + +describe('purge methods with raw content and default extractor with whitelisted patterns object', () => { + let purgecssResult + + beforeAll(() => { + purgecssResult = new Purgecss({ + content: [ + { + raw: '', + extension: 'html' + } + ], + css: [ + { + raw: `.single {color: black;} + .double-class test {color: red;} + .double-class.red {color: red;} + .double-class > .first-class {color: red;} + .double-class--black { background-color : black } + .double-class {color: black;}` + } + ], + whitelistPatterns : [ + { + pattern : /^double-class$/, + keepChildren : true + }, + ] + }).purge()[0].css + }) + + it ('keeps double-class children', () => { + expect(purgecssResult.includes('.double-class test')).toBe(true) + expect(purgecssResult.includes('.double-class.red')).toBe(true) + expect(purgecssResult.includes('.double-class > .first-class')).toBe(true) + }) + + it ('removes double-class--black class because of $', () => { + expect(purgecssResult.includes('.double-class--black')).toBe(false) + }) +}) + diff --git a/lib/purgecss.es.js b/lib/purgecss.es.js index 859a217e..a3247ae7 100644 --- a/lib/purgecss.es.js +++ b/lib/purgecss.es.js @@ -1 +1 @@ -import fs from"fs";import glob from"glob";import postcss from"postcss";import selectorParser from"postcss-selector-parser";function normalizeArray(e,t){for(var r=0,n=e.length-1;n>=0;n--){var o=e[n];"."===o?e.splice(n,1):".."===o?(e.splice(n,1),r++):r&&(e.splice(n,1),r--)}if(t)for(;r--;r)e.unshift("..");return e}var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,splitPath=function(e){return splitPathRe.exec(e).slice(1)};function resolve(){for(var e="",t=!1,r=arguments.length-1;r>=-1&&!t;r--){var n=r>=0?arguments[r]:"/";if("string"!=typeof n)throw new TypeError("Arguments to path.resolve must be strings");n&&(e=n+"/"+e,t="/"===n.charAt(0))}return e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"),(t?"/":"")+e||"."}function normalize(e){var t=isAbsolute(e),r="/"===substr(e,-1);return(e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"))||t||(e="."),e&&r&&(e+="/"),(t?"/":"")+e}function isAbsolute(e){return"/"===e.charAt(0)}function join(){return normalize(filter(Array.prototype.slice.call(arguments,0),function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e}).join("/"))}function relative(e,t){function r(e){for(var t=0;t=0&&""===e[r];r--);return t>r?[]:e.slice(t,r-t+1)}e=resolve(e).substr(1),t=resolve(t).substr(1);for(var n=r(e.split("/")),o=r(t.split("/")),i=Math.min(n.length,o.length),a=i,s=0;s1&&void 0!==arguments[1]?arguments[1]:[];return t.length?t.find(function(t){return t.extensions.find(function(t){return e.endsWith(t)})}).extractor:!0===this.options.legacy?LegacyExtractor:DefaultExtractor}},{key:"extractSelectors",value:function(e,t){var r=new Set,n=t.extract(e);if(null===n)throw new Error(ERROR_EXTRACTER_FAILED);return n.forEach(function(e){r.add(e)}),r.delete(""),r}},{key:"getSelectorsCss",value:function(e){var t=this;this.root.walk(function(r){return"rule"===r.type?t.evaluateRule(r,e):"atrule"===r.type?t.evaluateAtRule(r):void 0})}},{key:"evaluateRule",value:function(e,t){var r=this,n=e.prev();if(!this.isIgnoreAnnotation(n)){var o=!0;if(e.selector=selectorParser(function(e){e.walk(function(e){var n=[];if("selector"===e.type){if(e.parent&&":not"===e.parent.value&&"pseudo"===e.parent.type)return;var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.type,y=c.value;SELECTOR_STANDARD_TYPES.includes(f)&&void 0!==y?n.push(y):"tag"!==f||/[+]|(even)|(odd)|^from$|^to$|^\d/.test(y)||n.push(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}(o=r.shouldKeepSelector(t,n))||e.remove()}})}).processSync(e.selector),o){var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.prop,y=c.value;if(this.options.keyframes&&("animation"===f||"animation-name"===f)){var h=!0,p=!1,v=void 0;try{for(var d,E=y.split(" ")[Symbol.iterator]();!(h=(d=E.next()).done);h=!0){var R=d.value;this.usedAnimations.add(R)}}catch(e){p=!0,v=e}finally{try{!h&&E.return&&E.return()}finally{if(p)throw v}}}this.options.fontFace&&"font-family"===f&&this.usedFontFaces.add(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}}var m=e.parent;e.selector||e.remove(),this.isRuleEmpty(m)&&m.remove()}}},{key:"evaluateAtRule",value:function(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name){var t=!0,r=!1,n=void 0;try{for(var o,i=e.nodes[Symbol.iterator]();!(t=(o=i.next()).done);t=!0){var a=o.value,s=a.prop,l=a.value;"font-family"===s&&this.atRules.fontFace.push({name:l,node:e})}}catch(e){r=!0,n=e}finally{try{!t&&i.return&&i.return()}finally{if(r)throw n}}}else;}},{key:"isIgnoreAnnotation",value:function(e){return!(!e||"comment"!==e.type)&&e.text.includes(IGNORE_ANNOTATION)}},{key:"isRuleEmpty",value:function(e){return!!("decl"===e.type&&!e.value||"rule"===e.type&&!e.selector||e.nodes&&!e.nodes.length||"atrule"===e.type&&(!e.nodes&&!e.params||!e.params&&!e.nodes.length))}},{key:"shouldKeepSelector",value:function(e,t){var r=!0,n=!1,o=void 0;try{for(var i,a=t[Symbol.iterator]();!(r=(i=a.next()).done);r=!0){var s=i.value;if(this.options.legacy){var l=s.split(/[^a-z]/g),u=!1,c=!0,f=!1,y=void 0;try{for(var h,p=l[Symbol.iterator]();!(c=(h=p.next()).done);c=!0){var v=h.value;if(v){if(!e.has(v))break;u=!0}}}catch(e){f=!0,y=e}finally{try{!c&&p.return&&p.return()}finally{if(f)throw y}}if(u)return!0;if(e.has(s)||CSS_WHITELIST.includes(s)||this.isSelectorWhitelisted(s))return!0}else{var d=s.replace(/\\/g,"");if(d.startsWith(":"))continue;if(!(e.has(d)||CSS_WHITELIST.includes(d)||this.isSelectorWhitelisted(d)))return!1}}}catch(e){n=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(n)throw o}}return!this.options.legacy}},{key:"isSelectorWhitelisted",value:function(e){return!!(CSS_WHITELIST.includes(e)||this.options.whitelist&&this.options.whitelist.some(function(t){return t===e})||this.options.whitelistPatterns&&this.options.whitelistPatterns.some(function(t){return t.test(e)}))}}]),e}();export default Purgecss; +import fs from"fs";import glob from"glob";import postcss from"postcss";import selectorParser from"postcss-selector-parser";function normalizeArray(e,t){for(var r=0,n=e.length-1;n>=0;n--){var o=e[n];"."===o?e.splice(n,1):".."===o?(e.splice(n,1),r++):r&&(e.splice(n,1),r--)}if(t)for(;r--;r)e.unshift("..");return e}var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,splitPath=function(e){return splitPathRe.exec(e).slice(1)};function resolve(){for(var e="",t=!1,r=arguments.length-1;r>=-1&&!t;r--){var n=r>=0?arguments[r]:"/";if("string"!=typeof n)throw new TypeError("Arguments to path.resolve must be strings");n&&(e=n+"/"+e,t="/"===n.charAt(0))}return e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"),(t?"/":"")+e||"."}function normalize(e){var t=isAbsolute(e),r="/"===substr(e,-1);return(e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"))||t||(e="."),e&&r&&(e+="/"),(t?"/":"")+e}function isAbsolute(e){return"/"===e.charAt(0)}function join(){return normalize(filter(Array.prototype.slice.call(arguments,0),function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e}).join("/"))}function relative(e,t){function r(e){for(var t=0;t=0&&""===e[r];r--);return t>r?[]:e.slice(t,r-t+1)}e=resolve(e).substr(1),t=resolve(t).substr(1);for(var n=r(e.split("/")),o=r(t.split("/")),i=Math.min(n.length,o.length),a=i,s=0;s1&&void 0!==arguments[1]?arguments[1]:[];return t.length?t.find(function(t){return t.extensions.find(function(t){return e.endsWith(t)})}).extractor:!0===this.options.legacy?LegacyExtractor:DefaultExtractor}},{key:"extractSelectors",value:function(e,t){var r=new Set,n=t.extract(e);if(null===n)throw new Error(ERROR_EXTRACTER_FAILED);return n.forEach(function(e){r.add(e)}),r.delete(""),r}},{key:"getSelectorsCss",value:function(e){var t=this;this.root.walk(function(r){return"rule"===r.type?t.evaluateRule(r,e):"atrule"===r.type?t.evaluateAtRule(r):void 0})}},{key:"evaluateRule",value:function(e,t){var r=this,n=e.prev();if(!this.isIgnoreAnnotation(n)){var o=!0;if(e.selector=selectorParser(function(e){e.walk(function(e){var n=[];if("selector"===e.type){if(e.parent&&":not"===e.parent.value&&"pseudo"===e.parent.type)return;var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.type,y=c.value;SELECTOR_STANDARD_TYPES.includes(f)&&void 0!==y?n.push(y):"tag"!==f||/[+]|(even)|(odd)|^from$|^to$|^\d/.test(y)||n.push(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}(o=r.shouldKeepSelector(t,n))||e.remove()}})}).processSync(e.selector),o){var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.prop,y=c.value;if(this.options.keyframes&&("animation"===f||"animation-name"===f)){var h=!0,p=!1,v=void 0;try{for(var d,E=y.split(" ")[Symbol.iterator]();!(h=(d=E.next()).done);h=!0){var R=d.value;this.usedAnimations.add(R)}}catch(e){p=!0,v=e}finally{try{!h&&E.return&&E.return()}finally{if(p)throw v}}}this.options.fontFace&&"font-family"===f&&this.usedFontFaces.add(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}}var m=e.parent;e.selector||e.remove(),this.isRuleEmpty(m)&&m.remove()}}},{key:"evaluateAtRule",value:function(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name){var t=!0,r=!1,n=void 0;try{for(var o,i=e.nodes[Symbol.iterator]();!(t=(o=i.next()).done);t=!0){var a=o.value,s=a.prop,l=a.value;"font-family"===s&&this.atRules.fontFace.push({name:l,node:e})}}catch(e){r=!0,n=e}finally{try{!t&&i.return&&i.return()}finally{if(r)throw n}}}else;}},{key:"isIgnoreAnnotation",value:function(e){return!(!e||"comment"!==e.type)&&e.text.includes(IGNORE_ANNOTATION)}},{key:"isRuleEmpty",value:function(e){return!!("decl"===e.type&&!e.value||"rule"===e.type&&!e.selector||e.nodes&&!e.nodes.length||"atrule"===e.type&&(!e.nodes&&!e.params||!e.params&&!e.nodes.length))}},{key:"shouldKeepSelector",value:function(e,t){var r=!0,n=!1,o=void 0;try{for(var i,a=t[Symbol.iterator]();!(r=(i=a.next()).done);r=!0){var s=i.value;if(this.options.legacy){var l=s.split(/[^a-z]/g),u=!1,c=!0,f=!1,y=void 0;try{for(var h,p=l[Symbol.iterator]();!(c=(h=p.next()).done);c=!0){var v=h.value;if(v){if(!e.has(v))break;u=!0}}}catch(e){f=!0,y=e}finally{try{!c&&p.return&&p.return()}finally{if(f)throw y}}if(u)return!0;if(e.has(s)||CSS_WHITELIST.includes(s)||this.isSelectorWhitelisted(s))return!0}else{var d=s.replace(/\\/g,""),E=this.isSelectorWhitelisted(s);if(E&&this.hasSelectorKeepChildren(s))return!0;if(d.startsWith(":"))continue;if(!(e.has(d)||CSS_WHITELIST.includes(d)||E))return!1}}}catch(e){n=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(n)throw o}}return!this.options.legacy}},{key:"isSelectorWhitelisted",value:function(e){return this.getWhitelistedSelector(e).hasOwnProperty("pattern")}},{key:"getWhitelistedSelector",value:function(e){if(this.options.whitelist){var t=!0,r=!1,n=void 0;try{for(var o,i=this.options.whitelist[Symbol.iterator]();!(t=(o=i.next()).done);t=!0){var a=o.value,s="string"==typeof a,l=s?a:a.pattern;if(l===e)return s?{pattern:l}:a}}catch(e){r=!0,n=e}finally{try{!t&&i.return&&i.return()}finally{if(r)throw n}}}if(this.options.whitelistPatterns){var u=!0,c=!1,f=void 0;try{for(var y,h=this.options.whitelistPatterns[Symbol.iterator]();!(u=(y=h.next()).done);u=!0){var p=y.value,v=p instanceof RegExp,d=v?p:p.pattern;if(d.test(e))return v?{pattern:d}:p}}catch(e){c=!0,f=e}finally{try{!u&&h.return&&h.return()}finally{if(c)throw f}}}return{}}},{key:"hasSelectorKeepChildren",value:function(e){var t=this.getWhitelistedSelector(e);return!!t.hasOwnProperty("keepChildren")&&t.keepChildren}}]),e}();export default Purgecss; diff --git a/lib/purgecss.js b/lib/purgecss.js index abc70c7a..93ffb1d5 100644 --- a/lib/purgecss.js +++ b/lib/purgecss.js @@ -1 +1 @@ -"use strict";function _interopDefault(e){return e&&"object"==typeof e&&"default"in e?e.default:e}var fs=_interopDefault(require("fs")),glob=_interopDefault(require("glob")),postcss=_interopDefault(require("postcss")),selectorParser=_interopDefault(require("postcss-selector-parser"));function normalizeArray(e,t){for(var r=0,n=e.length-1;n>=0;n--){var o=e[n];"."===o?e.splice(n,1):".."===o?(e.splice(n,1),r++):r&&(e.splice(n,1),r--)}if(t)for(;r--;r)e.unshift("..");return e}var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,splitPath=function(e){return splitPathRe.exec(e).slice(1)};function resolve(){for(var e="",t=!1,r=arguments.length-1;r>=-1&&!t;r--){var n=r>=0?arguments[r]:"/";if("string"!=typeof n)throw new TypeError("Arguments to path.resolve must be strings");n&&(e=n+"/"+e,t="/"===n.charAt(0))}return e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"),(t?"/":"")+e||"."}function normalize(e){var t=isAbsolute(e),r="/"===substr(e,-1);return(e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"))||t||(e="."),e&&r&&(e+="/"),(t?"/":"")+e}function isAbsolute(e){return"/"===e.charAt(0)}function join(){return normalize(filter(Array.prototype.slice.call(arguments,0),function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e}).join("/"))}function relative(e,t){function r(e){for(var t=0;t=0&&""===e[r];r--);return t>r?[]:e.slice(t,r-t+1)}e=resolve(e).substr(1),t=resolve(t).substr(1);for(var n=r(e.split("/")),o=r(t.split("/")),i=Math.min(n.length,o.length),a=i,s=0;s1&&void 0!==arguments[1]?arguments[1]:[];return t.length?t.find(function(t){return t.extensions.find(function(t){return e.endsWith(t)})}).extractor:!0===this.options.legacy?LegacyExtractor:DefaultExtractor}},{key:"extractSelectors",value:function(e,t){var r=new Set,n=t.extract(e);if(null===n)throw new Error(ERROR_EXTRACTER_FAILED);return n.forEach(function(e){r.add(e)}),r.delete(""),r}},{key:"getSelectorsCss",value:function(e){var t=this;this.root.walk(function(r){return"rule"===r.type?t.evaluateRule(r,e):"atrule"===r.type?t.evaluateAtRule(r):void 0})}},{key:"evaluateRule",value:function(e,t){var r=this,n=e.prev();if(!this.isIgnoreAnnotation(n)){var o=!0;if(e.selector=selectorParser(function(e){e.walk(function(e){var n=[];if("selector"===e.type){if(e.parent&&":not"===e.parent.value&&"pseudo"===e.parent.type)return;var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.type,y=c.value;SELECTOR_STANDARD_TYPES.includes(f)&&void 0!==y?n.push(y):"tag"!==f||/[+]|(even)|(odd)|^from$|^to$|^\d/.test(y)||n.push(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}(o=r.shouldKeepSelector(t,n))||e.remove()}})}).processSync(e.selector),o){var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.prop,y=c.value;if(this.options.keyframes&&("animation"===f||"animation-name"===f)){var h=!0,p=!1,v=void 0;try{for(var d,E=y.split(" ")[Symbol.iterator]();!(h=(d=E.next()).done);h=!0){var R=d.value;this.usedAnimations.add(R)}}catch(e){p=!0,v=e}finally{try{!h&&E.return&&E.return()}finally{if(p)throw v}}}this.options.fontFace&&"font-family"===f&&this.usedFontFaces.add(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}}var m=e.parent;e.selector||e.remove(),this.isRuleEmpty(m)&&m.remove()}}},{key:"evaluateAtRule",value:function(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name){var t=!0,r=!1,n=void 0;try{for(var o,i=e.nodes[Symbol.iterator]();!(t=(o=i.next()).done);t=!0){var a=o.value,s=a.prop,l=a.value;"font-family"===s&&this.atRules.fontFace.push({name:l,node:e})}}catch(e){r=!0,n=e}finally{try{!t&&i.return&&i.return()}finally{if(r)throw n}}}else;}},{key:"isIgnoreAnnotation",value:function(e){return!(!e||"comment"!==e.type)&&e.text.includes(IGNORE_ANNOTATION)}},{key:"isRuleEmpty",value:function(e){return!!("decl"===e.type&&!e.value||"rule"===e.type&&!e.selector||e.nodes&&!e.nodes.length||"atrule"===e.type&&(!e.nodes&&!e.params||!e.params&&!e.nodes.length))}},{key:"shouldKeepSelector",value:function(e,t){var r=!0,n=!1,o=void 0;try{for(var i,a=t[Symbol.iterator]();!(r=(i=a.next()).done);r=!0){var s=i.value;if(this.options.legacy){var l=s.split(/[^a-z]/g),u=!1,c=!0,f=!1,y=void 0;try{for(var h,p=l[Symbol.iterator]();!(c=(h=p.next()).done);c=!0){var v=h.value;if(v){if(!e.has(v))break;u=!0}}}catch(e){f=!0,y=e}finally{try{!c&&p.return&&p.return()}finally{if(f)throw y}}if(u)return!0;if(e.has(s)||CSS_WHITELIST.includes(s)||this.isSelectorWhitelisted(s))return!0}else{var d=s.replace(/\\/g,"");if(d.startsWith(":"))continue;if(!(e.has(d)||CSS_WHITELIST.includes(d)||this.isSelectorWhitelisted(d)))return!1}}}catch(e){n=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(n)throw o}}return!this.options.legacy}},{key:"isSelectorWhitelisted",value:function(e){return!!(CSS_WHITELIST.includes(e)||this.options.whitelist&&this.options.whitelist.some(function(t){return t===e})||this.options.whitelistPatterns&&this.options.whitelistPatterns.some(function(t){return t.test(e)}))}}]),e}();module.exports=Purgecss; +"use strict";function _interopDefault(e){return e&&"object"==typeof e&&"default"in e?e.default:e}var fs=_interopDefault(require("fs")),glob=_interopDefault(require("glob")),postcss=_interopDefault(require("postcss")),selectorParser=_interopDefault(require("postcss-selector-parser"));function normalizeArray(e,t){for(var r=0,n=e.length-1;n>=0;n--){var o=e[n];"."===o?e.splice(n,1):".."===o?(e.splice(n,1),r++):r&&(e.splice(n,1),r--)}if(t)for(;r--;r)e.unshift("..");return e}var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,splitPath=function(e){return splitPathRe.exec(e).slice(1)};function resolve(){for(var e="",t=!1,r=arguments.length-1;r>=-1&&!t;r--){var n=r>=0?arguments[r]:"/";if("string"!=typeof n)throw new TypeError("Arguments to path.resolve must be strings");n&&(e=n+"/"+e,t="/"===n.charAt(0))}return e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"),(t?"/":"")+e||"."}function normalize(e){var t=isAbsolute(e),r="/"===substr(e,-1);return(e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"))||t||(e="."),e&&r&&(e+="/"),(t?"/":"")+e}function isAbsolute(e){return"/"===e.charAt(0)}function join(){return normalize(filter(Array.prototype.slice.call(arguments,0),function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e}).join("/"))}function relative(e,t){function r(e){for(var t=0;t=0&&""===e[r];r--);return t>r?[]:e.slice(t,r-t+1)}e=resolve(e).substr(1),t=resolve(t).substr(1);for(var n=r(e.split("/")),o=r(t.split("/")),i=Math.min(n.length,o.length),a=i,s=0;s1&&void 0!==arguments[1]?arguments[1]:[];return t.length?t.find(function(t){return t.extensions.find(function(t){return e.endsWith(t)})}).extractor:!0===this.options.legacy?LegacyExtractor:DefaultExtractor}},{key:"extractSelectors",value:function(e,t){var r=new Set,n=t.extract(e);if(null===n)throw new Error(ERROR_EXTRACTER_FAILED);return n.forEach(function(e){r.add(e)}),r.delete(""),r}},{key:"getSelectorsCss",value:function(e){var t=this;this.root.walk(function(r){return"rule"===r.type?t.evaluateRule(r,e):"atrule"===r.type?t.evaluateAtRule(r):void 0})}},{key:"evaluateRule",value:function(e,t){var r=this,n=e.prev();if(!this.isIgnoreAnnotation(n)){var o=!0;if(e.selector=selectorParser(function(e){e.walk(function(e){var n=[];if("selector"===e.type){if(e.parent&&":not"===e.parent.value&&"pseudo"===e.parent.type)return;var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.type,y=c.value;SELECTOR_STANDARD_TYPES.includes(f)&&void 0!==y?n.push(y):"tag"!==f||/[+]|(even)|(odd)|^from$|^to$|^\d/.test(y)||n.push(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}(o=r.shouldKeepSelector(t,n))||e.remove()}})}).processSync(e.selector),o){var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.prop,y=c.value;if(this.options.keyframes&&("animation"===f||"animation-name"===f)){var h=!0,p=!1,v=void 0;try{for(var d,E=y.split(" ")[Symbol.iterator]();!(h=(d=E.next()).done);h=!0){var R=d.value;this.usedAnimations.add(R)}}catch(e){p=!0,v=e}finally{try{!h&&E.return&&E.return()}finally{if(p)throw v}}}this.options.fontFace&&"font-family"===f&&this.usedFontFaces.add(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}}var m=e.parent;e.selector||e.remove(),this.isRuleEmpty(m)&&m.remove()}}},{key:"evaluateAtRule",value:function(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name){var t=!0,r=!1,n=void 0;try{for(var o,i=e.nodes[Symbol.iterator]();!(t=(o=i.next()).done);t=!0){var a=o.value,s=a.prop,l=a.value;"font-family"===s&&this.atRules.fontFace.push({name:l,node:e})}}catch(e){r=!0,n=e}finally{try{!t&&i.return&&i.return()}finally{if(r)throw n}}}else;}},{key:"isIgnoreAnnotation",value:function(e){return!(!e||"comment"!==e.type)&&e.text.includes(IGNORE_ANNOTATION)}},{key:"isRuleEmpty",value:function(e){return!!("decl"===e.type&&!e.value||"rule"===e.type&&!e.selector||e.nodes&&!e.nodes.length||"atrule"===e.type&&(!e.nodes&&!e.params||!e.params&&!e.nodes.length))}},{key:"shouldKeepSelector",value:function(e,t){var r=!0,n=!1,o=void 0;try{for(var i,a=t[Symbol.iterator]();!(r=(i=a.next()).done);r=!0){var s=i.value;if(this.options.legacy){var l=s.split(/[^a-z]/g),u=!1,c=!0,f=!1,y=void 0;try{for(var h,p=l[Symbol.iterator]();!(c=(h=p.next()).done);c=!0){var v=h.value;if(v){if(!e.has(v))break;u=!0}}}catch(e){f=!0,y=e}finally{try{!c&&p.return&&p.return()}finally{if(f)throw y}}if(u)return!0;if(e.has(s)||CSS_WHITELIST.includes(s)||this.isSelectorWhitelisted(s))return!0}else{var d=s.replace(/\\/g,""),E=this.isSelectorWhitelisted(s);if(E&&this.hasSelectorKeepChildren(s))return!0;if(d.startsWith(":"))continue;if(!(e.has(d)||CSS_WHITELIST.includes(d)||E))return!1}}}catch(e){n=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(n)throw o}}return!this.options.legacy}},{key:"isSelectorWhitelisted",value:function(e){return this.getWhitelistedSelector(e).hasOwnProperty("pattern")}},{key:"getWhitelistedSelector",value:function(e){if(this.options.whitelist){var t=!0,r=!1,n=void 0;try{for(var o,i=this.options.whitelist[Symbol.iterator]();!(t=(o=i.next()).done);t=!0){var a=o.value,s="string"==typeof a,l=s?a:a.pattern;if(l===e)return s?{pattern:l}:a}}catch(e){r=!0,n=e}finally{try{!t&&i.return&&i.return()}finally{if(r)throw n}}}if(this.options.whitelistPatterns){var u=!0,c=!1,f=void 0;try{for(var y,h=this.options.whitelistPatterns[Symbol.iterator]();!(u=(y=h.next()).done);u=!0){var p=y.value,v=p instanceof RegExp,d=v?p:p.pattern;if(d.test(e))return v?{pattern:d}:p}}catch(e){c=!0,f=e}finally{try{!u&&h.return&&h.return()}finally{if(c)throw f}}}return{}}},{key:"hasSelectorKeepChildren",value:function(e){var t=this.getWhitelistedSelector(e);return!!t.hasOwnProperty("keepChildren")&&t.keepChildren}}]),e}();module.exports=Purgecss; diff --git a/src/index.js b/src/index.js index 2107f9a3..03dfe087 100644 --- a/src/index.js +++ b/src/index.js @@ -406,12 +406,21 @@ class Purgecss { // non legacy extractors // pseudo class const unescapedSelector = selector.replace(/\\/g, '') + const isWhitelisted = this.isSelectorWhitelisted(selector) + + // As classes are read from left to right, we have to check the + // whitelist that passed the test and assert that children + // should be kept or not + if (isWhitelisted && this.hasSelectorKeepChildren(selector)) { + return true + } + if (unescapedSelector.startsWith(':')) continue if ( !( selectorsInContent.has(unescapedSelector) || CSS_WHITELIST.includes(unescapedSelector) || - this.isSelectorWhitelisted(unescapedSelector) + isWhitelisted ) ) { return false @@ -426,13 +435,50 @@ class Purgecss { * @param {string} selector css selector */ isSelectorWhitelisted(selector: string): boolean { - return !!( - CSS_WHITELIST.includes(selector) || - (this.options.whitelist && - this.options.whitelist.some((v: string) => v === selector)) || - (this.options.whitelistPatterns && - this.options.whitelistPatterns.some((v: RegExp) => v.test(selector))) - ) + return this.getWhitelistedSelector(selector).hasOwnProperty('pattern') + } + + /** + * Return whitelisted selector configuration + * + * @param {string} selector + */ + getWhitelistedSelector(selector: string): Object { + if (this.options.whitelist) { + for (const item of this.options.whitelist) { + const isString = (typeof item === 'string') + const pattern = (isString) ? item : item.pattern + + // Assert the pattern match the given selector + if (pattern === selector) { + return (isString) ? { pattern : pattern } : item + } + } + } + + if (this.options.whitelistPatterns) { + for (const item of this.options.whitelistPatterns) { + const isRegExp = (item instanceof RegExp) + const pattern = (isRegExp) ? item : item.pattern + + // Assert the pattern match the given selector + if (pattern.test(selector)) { + return (isRegExp) ? { pattern : pattern } : item + } + } + } + + return {} + } + + /** + * Return corresponding whitelisted pattern if exists + * + * @param {string} selector + */ + hasSelectorKeepChildren(selector: string): Object { + const whitelist = this.getWhitelistedSelector(selector) + return (whitelist.hasOwnProperty('keepChildren')) ? whitelist.keepChildren : false } } From 89109a8f19e0dd6922d344481537fdfaf2cbe57b Mon Sep 17 00:00:00 2001 From: Cyril Mizzi Date: Mon, 26 Feb 2018 18:05:19 +0100 Subject: [PATCH 2/6] fixes style code --- __tests__/purgecssDefault.test.js | 13 ++++++------- src/index.js | 14 +++++++------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/__tests__/purgecssDefault.test.js b/__tests__/purgecssDefault.test.js index 09cd8110..a7b4efcd 100644 --- a/__tests__/purgecssDefault.test.js +++ b/__tests__/purgecssDefault.test.js @@ -357,23 +357,22 @@ describe('purge methods with raw content and default extractor with whitelisted .double-class {color: black;}` } ], - whitelistPatterns : [ + whitelistPatterns: [ { - pattern : /^double-class$/, - keepChildren : true - }, + pattern: /^double-class$/, + keepChildren: true + } ] }).purge()[0].css }) - it ('keeps double-class children', () => { + it('keeps double-class children', () => { expect(purgecssResult.includes('.double-class test')).toBe(true) expect(purgecssResult.includes('.double-class.red')).toBe(true) expect(purgecssResult.includes('.double-class > .first-class')).toBe(true) }) - it ('removes double-class--black class because of $', () => { + it('removes double-class--black class because of $', () => { expect(purgecssResult.includes('.double-class--black')).toBe(false) }) }) - diff --git a/src/index.js b/src/index.js index 03dfe087..6c380593 100644 --- a/src/index.js +++ b/src/index.js @@ -446,24 +446,24 @@ class Purgecss { getWhitelistedSelector(selector: string): Object { if (this.options.whitelist) { for (const item of this.options.whitelist) { - const isString = (typeof item === 'string') - const pattern = (isString) ? item : item.pattern + const isString = typeof item === 'string' + const pattern = isString ? item : item.pattern // Assert the pattern match the given selector if (pattern === selector) { - return (isString) ? { pattern : pattern } : item + return isString ? { pattern: pattern } : item } } } if (this.options.whitelistPatterns) { for (const item of this.options.whitelistPatterns) { - const isRegExp = (item instanceof RegExp) - const pattern = (isRegExp) ? item : item.pattern + const isRegExp = item instanceof RegExp + const pattern = isRegExp ? item : item.pattern // Assert the pattern match the given selector if (pattern.test(selector)) { - return (isRegExp) ? { pattern : pattern } : item + return isRegExp ? { pattern: pattern } : item } } } @@ -478,7 +478,7 @@ class Purgecss { */ hasSelectorKeepChildren(selector: string): Object { const whitelist = this.getWhitelistedSelector(selector) - return (whitelist.hasOwnProperty('keepChildren')) ? whitelist.keepChildren : false + return whitelist.hasOwnProperty('keepChildren') ? whitelist.keepChildren : false } } From 2213be632b4bf6ec28d06c63866fdd4e85c2adfc Mon Sep 17 00:00:00 2001 From: Cyril Mizzi Date: Wed, 14 Mar 2018 11:42:59 +0100 Subject: [PATCH 3/6] Revert "fixes style code" This reverts commit 89109a8f19e0dd6922d344481537fdfaf2cbe57b. --- __tests__/purgecssDefault.test.js | 13 +++++++------ src/index.js | 14 +++++++------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/__tests__/purgecssDefault.test.js b/__tests__/purgecssDefault.test.js index a7b4efcd..09cd8110 100644 --- a/__tests__/purgecssDefault.test.js +++ b/__tests__/purgecssDefault.test.js @@ -357,22 +357,23 @@ describe('purge methods with raw content and default extractor with whitelisted .double-class {color: black;}` } ], - whitelistPatterns: [ + whitelistPatterns : [ { - pattern: /^double-class$/, - keepChildren: true - } + pattern : /^double-class$/, + keepChildren : true + }, ] }).purge()[0].css }) - it('keeps double-class children', () => { + it ('keeps double-class children', () => { expect(purgecssResult.includes('.double-class test')).toBe(true) expect(purgecssResult.includes('.double-class.red')).toBe(true) expect(purgecssResult.includes('.double-class > .first-class')).toBe(true) }) - it('removes double-class--black class because of $', () => { + it ('removes double-class--black class because of $', () => { expect(purgecssResult.includes('.double-class--black')).toBe(false) }) }) + diff --git a/src/index.js b/src/index.js index 6c380593..03dfe087 100644 --- a/src/index.js +++ b/src/index.js @@ -446,24 +446,24 @@ class Purgecss { getWhitelistedSelector(selector: string): Object { if (this.options.whitelist) { for (const item of this.options.whitelist) { - const isString = typeof item === 'string' - const pattern = isString ? item : item.pattern + const isString = (typeof item === 'string') + const pattern = (isString) ? item : item.pattern // Assert the pattern match the given selector if (pattern === selector) { - return isString ? { pattern: pattern } : item + return (isString) ? { pattern : pattern } : item } } } if (this.options.whitelistPatterns) { for (const item of this.options.whitelistPatterns) { - const isRegExp = item instanceof RegExp - const pattern = isRegExp ? item : item.pattern + const isRegExp = (item instanceof RegExp) + const pattern = (isRegExp) ? item : item.pattern // Assert the pattern match the given selector if (pattern.test(selector)) { - return isRegExp ? { pattern: pattern } : item + return (isRegExp) ? { pattern : pattern } : item } } } @@ -478,7 +478,7 @@ class Purgecss { */ hasSelectorKeepChildren(selector: string): Object { const whitelist = this.getWhitelistedSelector(selector) - return whitelist.hasOwnProperty('keepChildren') ? whitelist.keepChildren : false + return (whitelist.hasOwnProperty('keepChildren')) ? whitelist.keepChildren : false } } From c52c81b248ba01ded6e6ac4965871af426821eec Mon Sep 17 00:00:00 2001 From: Cyril Mizzi Date: Wed, 14 Mar 2018 11:43:14 +0100 Subject: [PATCH 4/6] Revert "adds keepChildren ability from whitelistPatterns Object[]" This reverts commit 9503c17bdfb45bb157df4393278403a93272276a. --- __tests__/purgecssDefault.test.js | 42 --------------------- lib/purgecss.es.js | 2 +- lib/purgecss.js | 2 +- src/index.js | 62 ++++--------------------------- 4 files changed, 10 insertions(+), 98 deletions(-) diff --git a/__tests__/purgecssDefault.test.js b/__tests__/purgecssDefault.test.js index 09cd8110..76bc448c 100644 --- a/__tests__/purgecssDefault.test.js +++ b/__tests__/purgecssDefault.test.js @@ -335,45 +335,3 @@ describe('purge methods with raw content and default extractor', () => { expect(purgecssResult.includes('double-class')).toBe(true) }) }) - -describe('purge methods with raw content and default extractor with whitelisted patterns object', () => { - let purgecssResult - - beforeAll(() => { - purgecssResult = new Purgecss({ - content: [ - { - raw: '', - extension: 'html' - } - ], - css: [ - { - raw: `.single {color: black;} - .double-class test {color: red;} - .double-class.red {color: red;} - .double-class > .first-class {color: red;} - .double-class--black { background-color : black } - .double-class {color: black;}` - } - ], - whitelistPatterns : [ - { - pattern : /^double-class$/, - keepChildren : true - }, - ] - }).purge()[0].css - }) - - it ('keeps double-class children', () => { - expect(purgecssResult.includes('.double-class test')).toBe(true) - expect(purgecssResult.includes('.double-class.red')).toBe(true) - expect(purgecssResult.includes('.double-class > .first-class')).toBe(true) - }) - - it ('removes double-class--black class because of $', () => { - expect(purgecssResult.includes('.double-class--black')).toBe(false) - }) -}) - diff --git a/lib/purgecss.es.js b/lib/purgecss.es.js index a3247ae7..859a217e 100644 --- a/lib/purgecss.es.js +++ b/lib/purgecss.es.js @@ -1 +1 @@ -import fs from"fs";import glob from"glob";import postcss from"postcss";import selectorParser from"postcss-selector-parser";function normalizeArray(e,t){for(var r=0,n=e.length-1;n>=0;n--){var o=e[n];"."===o?e.splice(n,1):".."===o?(e.splice(n,1),r++):r&&(e.splice(n,1),r--)}if(t)for(;r--;r)e.unshift("..");return e}var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,splitPath=function(e){return splitPathRe.exec(e).slice(1)};function resolve(){for(var e="",t=!1,r=arguments.length-1;r>=-1&&!t;r--){var n=r>=0?arguments[r]:"/";if("string"!=typeof n)throw new TypeError("Arguments to path.resolve must be strings");n&&(e=n+"/"+e,t="/"===n.charAt(0))}return e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"),(t?"/":"")+e||"."}function normalize(e){var t=isAbsolute(e),r="/"===substr(e,-1);return(e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"))||t||(e="."),e&&r&&(e+="/"),(t?"/":"")+e}function isAbsolute(e){return"/"===e.charAt(0)}function join(){return normalize(filter(Array.prototype.slice.call(arguments,0),function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e}).join("/"))}function relative(e,t){function r(e){for(var t=0;t=0&&""===e[r];r--);return t>r?[]:e.slice(t,r-t+1)}e=resolve(e).substr(1),t=resolve(t).substr(1);for(var n=r(e.split("/")),o=r(t.split("/")),i=Math.min(n.length,o.length),a=i,s=0;s1&&void 0!==arguments[1]?arguments[1]:[];return t.length?t.find(function(t){return t.extensions.find(function(t){return e.endsWith(t)})}).extractor:!0===this.options.legacy?LegacyExtractor:DefaultExtractor}},{key:"extractSelectors",value:function(e,t){var r=new Set,n=t.extract(e);if(null===n)throw new Error(ERROR_EXTRACTER_FAILED);return n.forEach(function(e){r.add(e)}),r.delete(""),r}},{key:"getSelectorsCss",value:function(e){var t=this;this.root.walk(function(r){return"rule"===r.type?t.evaluateRule(r,e):"atrule"===r.type?t.evaluateAtRule(r):void 0})}},{key:"evaluateRule",value:function(e,t){var r=this,n=e.prev();if(!this.isIgnoreAnnotation(n)){var o=!0;if(e.selector=selectorParser(function(e){e.walk(function(e){var n=[];if("selector"===e.type){if(e.parent&&":not"===e.parent.value&&"pseudo"===e.parent.type)return;var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.type,y=c.value;SELECTOR_STANDARD_TYPES.includes(f)&&void 0!==y?n.push(y):"tag"!==f||/[+]|(even)|(odd)|^from$|^to$|^\d/.test(y)||n.push(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}(o=r.shouldKeepSelector(t,n))||e.remove()}})}).processSync(e.selector),o){var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.prop,y=c.value;if(this.options.keyframes&&("animation"===f||"animation-name"===f)){var h=!0,p=!1,v=void 0;try{for(var d,E=y.split(" ")[Symbol.iterator]();!(h=(d=E.next()).done);h=!0){var R=d.value;this.usedAnimations.add(R)}}catch(e){p=!0,v=e}finally{try{!h&&E.return&&E.return()}finally{if(p)throw v}}}this.options.fontFace&&"font-family"===f&&this.usedFontFaces.add(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}}var m=e.parent;e.selector||e.remove(),this.isRuleEmpty(m)&&m.remove()}}},{key:"evaluateAtRule",value:function(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name){var t=!0,r=!1,n=void 0;try{for(var o,i=e.nodes[Symbol.iterator]();!(t=(o=i.next()).done);t=!0){var a=o.value,s=a.prop,l=a.value;"font-family"===s&&this.atRules.fontFace.push({name:l,node:e})}}catch(e){r=!0,n=e}finally{try{!t&&i.return&&i.return()}finally{if(r)throw n}}}else;}},{key:"isIgnoreAnnotation",value:function(e){return!(!e||"comment"!==e.type)&&e.text.includes(IGNORE_ANNOTATION)}},{key:"isRuleEmpty",value:function(e){return!!("decl"===e.type&&!e.value||"rule"===e.type&&!e.selector||e.nodes&&!e.nodes.length||"atrule"===e.type&&(!e.nodes&&!e.params||!e.params&&!e.nodes.length))}},{key:"shouldKeepSelector",value:function(e,t){var r=!0,n=!1,o=void 0;try{for(var i,a=t[Symbol.iterator]();!(r=(i=a.next()).done);r=!0){var s=i.value;if(this.options.legacy){var l=s.split(/[^a-z]/g),u=!1,c=!0,f=!1,y=void 0;try{for(var h,p=l[Symbol.iterator]();!(c=(h=p.next()).done);c=!0){var v=h.value;if(v){if(!e.has(v))break;u=!0}}}catch(e){f=!0,y=e}finally{try{!c&&p.return&&p.return()}finally{if(f)throw y}}if(u)return!0;if(e.has(s)||CSS_WHITELIST.includes(s)||this.isSelectorWhitelisted(s))return!0}else{var d=s.replace(/\\/g,""),E=this.isSelectorWhitelisted(s);if(E&&this.hasSelectorKeepChildren(s))return!0;if(d.startsWith(":"))continue;if(!(e.has(d)||CSS_WHITELIST.includes(d)||E))return!1}}}catch(e){n=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(n)throw o}}return!this.options.legacy}},{key:"isSelectorWhitelisted",value:function(e){return this.getWhitelistedSelector(e).hasOwnProperty("pattern")}},{key:"getWhitelistedSelector",value:function(e){if(this.options.whitelist){var t=!0,r=!1,n=void 0;try{for(var o,i=this.options.whitelist[Symbol.iterator]();!(t=(o=i.next()).done);t=!0){var a=o.value,s="string"==typeof a,l=s?a:a.pattern;if(l===e)return s?{pattern:l}:a}}catch(e){r=!0,n=e}finally{try{!t&&i.return&&i.return()}finally{if(r)throw n}}}if(this.options.whitelistPatterns){var u=!0,c=!1,f=void 0;try{for(var y,h=this.options.whitelistPatterns[Symbol.iterator]();!(u=(y=h.next()).done);u=!0){var p=y.value,v=p instanceof RegExp,d=v?p:p.pattern;if(d.test(e))return v?{pattern:d}:p}}catch(e){c=!0,f=e}finally{try{!u&&h.return&&h.return()}finally{if(c)throw f}}}return{}}},{key:"hasSelectorKeepChildren",value:function(e){var t=this.getWhitelistedSelector(e);return!!t.hasOwnProperty("keepChildren")&&t.keepChildren}}]),e}();export default Purgecss; +import fs from"fs";import glob from"glob";import postcss from"postcss";import selectorParser from"postcss-selector-parser";function normalizeArray(e,t){for(var r=0,n=e.length-1;n>=0;n--){var o=e[n];"."===o?e.splice(n,1):".."===o?(e.splice(n,1),r++):r&&(e.splice(n,1),r--)}if(t)for(;r--;r)e.unshift("..");return e}var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,splitPath=function(e){return splitPathRe.exec(e).slice(1)};function resolve(){for(var e="",t=!1,r=arguments.length-1;r>=-1&&!t;r--){var n=r>=0?arguments[r]:"/";if("string"!=typeof n)throw new TypeError("Arguments to path.resolve must be strings");n&&(e=n+"/"+e,t="/"===n.charAt(0))}return e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"),(t?"/":"")+e||"."}function normalize(e){var t=isAbsolute(e),r="/"===substr(e,-1);return(e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"))||t||(e="."),e&&r&&(e+="/"),(t?"/":"")+e}function isAbsolute(e){return"/"===e.charAt(0)}function join(){return normalize(filter(Array.prototype.slice.call(arguments,0),function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e}).join("/"))}function relative(e,t){function r(e){for(var t=0;t=0&&""===e[r];r--);return t>r?[]:e.slice(t,r-t+1)}e=resolve(e).substr(1),t=resolve(t).substr(1);for(var n=r(e.split("/")),o=r(t.split("/")),i=Math.min(n.length,o.length),a=i,s=0;s1&&void 0!==arguments[1]?arguments[1]:[];return t.length?t.find(function(t){return t.extensions.find(function(t){return e.endsWith(t)})}).extractor:!0===this.options.legacy?LegacyExtractor:DefaultExtractor}},{key:"extractSelectors",value:function(e,t){var r=new Set,n=t.extract(e);if(null===n)throw new Error(ERROR_EXTRACTER_FAILED);return n.forEach(function(e){r.add(e)}),r.delete(""),r}},{key:"getSelectorsCss",value:function(e){var t=this;this.root.walk(function(r){return"rule"===r.type?t.evaluateRule(r,e):"atrule"===r.type?t.evaluateAtRule(r):void 0})}},{key:"evaluateRule",value:function(e,t){var r=this,n=e.prev();if(!this.isIgnoreAnnotation(n)){var o=!0;if(e.selector=selectorParser(function(e){e.walk(function(e){var n=[];if("selector"===e.type){if(e.parent&&":not"===e.parent.value&&"pseudo"===e.parent.type)return;var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.type,y=c.value;SELECTOR_STANDARD_TYPES.includes(f)&&void 0!==y?n.push(y):"tag"!==f||/[+]|(even)|(odd)|^from$|^to$|^\d/.test(y)||n.push(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}(o=r.shouldKeepSelector(t,n))||e.remove()}})}).processSync(e.selector),o){var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.prop,y=c.value;if(this.options.keyframes&&("animation"===f||"animation-name"===f)){var h=!0,p=!1,v=void 0;try{for(var d,E=y.split(" ")[Symbol.iterator]();!(h=(d=E.next()).done);h=!0){var R=d.value;this.usedAnimations.add(R)}}catch(e){p=!0,v=e}finally{try{!h&&E.return&&E.return()}finally{if(p)throw v}}}this.options.fontFace&&"font-family"===f&&this.usedFontFaces.add(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}}var m=e.parent;e.selector||e.remove(),this.isRuleEmpty(m)&&m.remove()}}},{key:"evaluateAtRule",value:function(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name){var t=!0,r=!1,n=void 0;try{for(var o,i=e.nodes[Symbol.iterator]();!(t=(o=i.next()).done);t=!0){var a=o.value,s=a.prop,l=a.value;"font-family"===s&&this.atRules.fontFace.push({name:l,node:e})}}catch(e){r=!0,n=e}finally{try{!t&&i.return&&i.return()}finally{if(r)throw n}}}else;}},{key:"isIgnoreAnnotation",value:function(e){return!(!e||"comment"!==e.type)&&e.text.includes(IGNORE_ANNOTATION)}},{key:"isRuleEmpty",value:function(e){return!!("decl"===e.type&&!e.value||"rule"===e.type&&!e.selector||e.nodes&&!e.nodes.length||"atrule"===e.type&&(!e.nodes&&!e.params||!e.params&&!e.nodes.length))}},{key:"shouldKeepSelector",value:function(e,t){var r=!0,n=!1,o=void 0;try{for(var i,a=t[Symbol.iterator]();!(r=(i=a.next()).done);r=!0){var s=i.value;if(this.options.legacy){var l=s.split(/[^a-z]/g),u=!1,c=!0,f=!1,y=void 0;try{for(var h,p=l[Symbol.iterator]();!(c=(h=p.next()).done);c=!0){var v=h.value;if(v){if(!e.has(v))break;u=!0}}}catch(e){f=!0,y=e}finally{try{!c&&p.return&&p.return()}finally{if(f)throw y}}if(u)return!0;if(e.has(s)||CSS_WHITELIST.includes(s)||this.isSelectorWhitelisted(s))return!0}else{var d=s.replace(/\\/g,"");if(d.startsWith(":"))continue;if(!(e.has(d)||CSS_WHITELIST.includes(d)||this.isSelectorWhitelisted(d)))return!1}}}catch(e){n=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(n)throw o}}return!this.options.legacy}},{key:"isSelectorWhitelisted",value:function(e){return!!(CSS_WHITELIST.includes(e)||this.options.whitelist&&this.options.whitelist.some(function(t){return t===e})||this.options.whitelistPatterns&&this.options.whitelistPatterns.some(function(t){return t.test(e)}))}}]),e}();export default Purgecss; diff --git a/lib/purgecss.js b/lib/purgecss.js index 93ffb1d5..abc70c7a 100644 --- a/lib/purgecss.js +++ b/lib/purgecss.js @@ -1 +1 @@ -"use strict";function _interopDefault(e){return e&&"object"==typeof e&&"default"in e?e.default:e}var fs=_interopDefault(require("fs")),glob=_interopDefault(require("glob")),postcss=_interopDefault(require("postcss")),selectorParser=_interopDefault(require("postcss-selector-parser"));function normalizeArray(e,t){for(var r=0,n=e.length-1;n>=0;n--){var o=e[n];"."===o?e.splice(n,1):".."===o?(e.splice(n,1),r++):r&&(e.splice(n,1),r--)}if(t)for(;r--;r)e.unshift("..");return e}var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,splitPath=function(e){return splitPathRe.exec(e).slice(1)};function resolve(){for(var e="",t=!1,r=arguments.length-1;r>=-1&&!t;r--){var n=r>=0?arguments[r]:"/";if("string"!=typeof n)throw new TypeError("Arguments to path.resolve must be strings");n&&(e=n+"/"+e,t="/"===n.charAt(0))}return e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"),(t?"/":"")+e||"."}function normalize(e){var t=isAbsolute(e),r="/"===substr(e,-1);return(e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"))||t||(e="."),e&&r&&(e+="/"),(t?"/":"")+e}function isAbsolute(e){return"/"===e.charAt(0)}function join(){return normalize(filter(Array.prototype.slice.call(arguments,0),function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e}).join("/"))}function relative(e,t){function r(e){for(var t=0;t=0&&""===e[r];r--);return t>r?[]:e.slice(t,r-t+1)}e=resolve(e).substr(1),t=resolve(t).substr(1);for(var n=r(e.split("/")),o=r(t.split("/")),i=Math.min(n.length,o.length),a=i,s=0;s1&&void 0!==arguments[1]?arguments[1]:[];return t.length?t.find(function(t){return t.extensions.find(function(t){return e.endsWith(t)})}).extractor:!0===this.options.legacy?LegacyExtractor:DefaultExtractor}},{key:"extractSelectors",value:function(e,t){var r=new Set,n=t.extract(e);if(null===n)throw new Error(ERROR_EXTRACTER_FAILED);return n.forEach(function(e){r.add(e)}),r.delete(""),r}},{key:"getSelectorsCss",value:function(e){var t=this;this.root.walk(function(r){return"rule"===r.type?t.evaluateRule(r,e):"atrule"===r.type?t.evaluateAtRule(r):void 0})}},{key:"evaluateRule",value:function(e,t){var r=this,n=e.prev();if(!this.isIgnoreAnnotation(n)){var o=!0;if(e.selector=selectorParser(function(e){e.walk(function(e){var n=[];if("selector"===e.type){if(e.parent&&":not"===e.parent.value&&"pseudo"===e.parent.type)return;var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.type,y=c.value;SELECTOR_STANDARD_TYPES.includes(f)&&void 0!==y?n.push(y):"tag"!==f||/[+]|(even)|(odd)|^from$|^to$|^\d/.test(y)||n.push(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}(o=r.shouldKeepSelector(t,n))||e.remove()}})}).processSync(e.selector),o){var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.prop,y=c.value;if(this.options.keyframes&&("animation"===f||"animation-name"===f)){var h=!0,p=!1,v=void 0;try{for(var d,E=y.split(" ")[Symbol.iterator]();!(h=(d=E.next()).done);h=!0){var R=d.value;this.usedAnimations.add(R)}}catch(e){p=!0,v=e}finally{try{!h&&E.return&&E.return()}finally{if(p)throw v}}}this.options.fontFace&&"font-family"===f&&this.usedFontFaces.add(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}}var m=e.parent;e.selector||e.remove(),this.isRuleEmpty(m)&&m.remove()}}},{key:"evaluateAtRule",value:function(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name){var t=!0,r=!1,n=void 0;try{for(var o,i=e.nodes[Symbol.iterator]();!(t=(o=i.next()).done);t=!0){var a=o.value,s=a.prop,l=a.value;"font-family"===s&&this.atRules.fontFace.push({name:l,node:e})}}catch(e){r=!0,n=e}finally{try{!t&&i.return&&i.return()}finally{if(r)throw n}}}else;}},{key:"isIgnoreAnnotation",value:function(e){return!(!e||"comment"!==e.type)&&e.text.includes(IGNORE_ANNOTATION)}},{key:"isRuleEmpty",value:function(e){return!!("decl"===e.type&&!e.value||"rule"===e.type&&!e.selector||e.nodes&&!e.nodes.length||"atrule"===e.type&&(!e.nodes&&!e.params||!e.params&&!e.nodes.length))}},{key:"shouldKeepSelector",value:function(e,t){var r=!0,n=!1,o=void 0;try{for(var i,a=t[Symbol.iterator]();!(r=(i=a.next()).done);r=!0){var s=i.value;if(this.options.legacy){var l=s.split(/[^a-z]/g),u=!1,c=!0,f=!1,y=void 0;try{for(var h,p=l[Symbol.iterator]();!(c=(h=p.next()).done);c=!0){var v=h.value;if(v){if(!e.has(v))break;u=!0}}}catch(e){f=!0,y=e}finally{try{!c&&p.return&&p.return()}finally{if(f)throw y}}if(u)return!0;if(e.has(s)||CSS_WHITELIST.includes(s)||this.isSelectorWhitelisted(s))return!0}else{var d=s.replace(/\\/g,""),E=this.isSelectorWhitelisted(s);if(E&&this.hasSelectorKeepChildren(s))return!0;if(d.startsWith(":"))continue;if(!(e.has(d)||CSS_WHITELIST.includes(d)||E))return!1}}}catch(e){n=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(n)throw o}}return!this.options.legacy}},{key:"isSelectorWhitelisted",value:function(e){return this.getWhitelistedSelector(e).hasOwnProperty("pattern")}},{key:"getWhitelistedSelector",value:function(e){if(this.options.whitelist){var t=!0,r=!1,n=void 0;try{for(var o,i=this.options.whitelist[Symbol.iterator]();!(t=(o=i.next()).done);t=!0){var a=o.value,s="string"==typeof a,l=s?a:a.pattern;if(l===e)return s?{pattern:l}:a}}catch(e){r=!0,n=e}finally{try{!t&&i.return&&i.return()}finally{if(r)throw n}}}if(this.options.whitelistPatterns){var u=!0,c=!1,f=void 0;try{for(var y,h=this.options.whitelistPatterns[Symbol.iterator]();!(u=(y=h.next()).done);u=!0){var p=y.value,v=p instanceof RegExp,d=v?p:p.pattern;if(d.test(e))return v?{pattern:d}:p}}catch(e){c=!0,f=e}finally{try{!u&&h.return&&h.return()}finally{if(c)throw f}}}return{}}},{key:"hasSelectorKeepChildren",value:function(e){var t=this.getWhitelistedSelector(e);return!!t.hasOwnProperty("keepChildren")&&t.keepChildren}}]),e}();module.exports=Purgecss; +"use strict";function _interopDefault(e){return e&&"object"==typeof e&&"default"in e?e.default:e}var fs=_interopDefault(require("fs")),glob=_interopDefault(require("glob")),postcss=_interopDefault(require("postcss")),selectorParser=_interopDefault(require("postcss-selector-parser"));function normalizeArray(e,t){for(var r=0,n=e.length-1;n>=0;n--){var o=e[n];"."===o?e.splice(n,1):".."===o?(e.splice(n,1),r++):r&&(e.splice(n,1),r--)}if(t)for(;r--;r)e.unshift("..");return e}var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,splitPath=function(e){return splitPathRe.exec(e).slice(1)};function resolve(){for(var e="",t=!1,r=arguments.length-1;r>=-1&&!t;r--){var n=r>=0?arguments[r]:"/";if("string"!=typeof n)throw new TypeError("Arguments to path.resolve must be strings");n&&(e=n+"/"+e,t="/"===n.charAt(0))}return e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"),(t?"/":"")+e||"."}function normalize(e){var t=isAbsolute(e),r="/"===substr(e,-1);return(e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"))||t||(e="."),e&&r&&(e+="/"),(t?"/":"")+e}function isAbsolute(e){return"/"===e.charAt(0)}function join(){return normalize(filter(Array.prototype.slice.call(arguments,0),function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e}).join("/"))}function relative(e,t){function r(e){for(var t=0;t=0&&""===e[r];r--);return t>r?[]:e.slice(t,r-t+1)}e=resolve(e).substr(1),t=resolve(t).substr(1);for(var n=r(e.split("/")),o=r(t.split("/")),i=Math.min(n.length,o.length),a=i,s=0;s1&&void 0!==arguments[1]?arguments[1]:[];return t.length?t.find(function(t){return t.extensions.find(function(t){return e.endsWith(t)})}).extractor:!0===this.options.legacy?LegacyExtractor:DefaultExtractor}},{key:"extractSelectors",value:function(e,t){var r=new Set,n=t.extract(e);if(null===n)throw new Error(ERROR_EXTRACTER_FAILED);return n.forEach(function(e){r.add(e)}),r.delete(""),r}},{key:"getSelectorsCss",value:function(e){var t=this;this.root.walk(function(r){return"rule"===r.type?t.evaluateRule(r,e):"atrule"===r.type?t.evaluateAtRule(r):void 0})}},{key:"evaluateRule",value:function(e,t){var r=this,n=e.prev();if(!this.isIgnoreAnnotation(n)){var o=!0;if(e.selector=selectorParser(function(e){e.walk(function(e){var n=[];if("selector"===e.type){if(e.parent&&":not"===e.parent.value&&"pseudo"===e.parent.type)return;var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.type,y=c.value;SELECTOR_STANDARD_TYPES.includes(f)&&void 0!==y?n.push(y):"tag"!==f||/[+]|(even)|(odd)|^from$|^to$|^\d/.test(y)||n.push(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}(o=r.shouldKeepSelector(t,n))||e.remove()}})}).processSync(e.selector),o){var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.prop,y=c.value;if(this.options.keyframes&&("animation"===f||"animation-name"===f)){var h=!0,p=!1,v=void 0;try{for(var d,E=y.split(" ")[Symbol.iterator]();!(h=(d=E.next()).done);h=!0){var R=d.value;this.usedAnimations.add(R)}}catch(e){p=!0,v=e}finally{try{!h&&E.return&&E.return()}finally{if(p)throw v}}}this.options.fontFace&&"font-family"===f&&this.usedFontFaces.add(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}}var m=e.parent;e.selector||e.remove(),this.isRuleEmpty(m)&&m.remove()}}},{key:"evaluateAtRule",value:function(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name){var t=!0,r=!1,n=void 0;try{for(var o,i=e.nodes[Symbol.iterator]();!(t=(o=i.next()).done);t=!0){var a=o.value,s=a.prop,l=a.value;"font-family"===s&&this.atRules.fontFace.push({name:l,node:e})}}catch(e){r=!0,n=e}finally{try{!t&&i.return&&i.return()}finally{if(r)throw n}}}else;}},{key:"isIgnoreAnnotation",value:function(e){return!(!e||"comment"!==e.type)&&e.text.includes(IGNORE_ANNOTATION)}},{key:"isRuleEmpty",value:function(e){return!!("decl"===e.type&&!e.value||"rule"===e.type&&!e.selector||e.nodes&&!e.nodes.length||"atrule"===e.type&&(!e.nodes&&!e.params||!e.params&&!e.nodes.length))}},{key:"shouldKeepSelector",value:function(e,t){var r=!0,n=!1,o=void 0;try{for(var i,a=t[Symbol.iterator]();!(r=(i=a.next()).done);r=!0){var s=i.value;if(this.options.legacy){var l=s.split(/[^a-z]/g),u=!1,c=!0,f=!1,y=void 0;try{for(var h,p=l[Symbol.iterator]();!(c=(h=p.next()).done);c=!0){var v=h.value;if(v){if(!e.has(v))break;u=!0}}}catch(e){f=!0,y=e}finally{try{!c&&p.return&&p.return()}finally{if(f)throw y}}if(u)return!0;if(e.has(s)||CSS_WHITELIST.includes(s)||this.isSelectorWhitelisted(s))return!0}else{var d=s.replace(/\\/g,"");if(d.startsWith(":"))continue;if(!(e.has(d)||CSS_WHITELIST.includes(d)||this.isSelectorWhitelisted(d)))return!1}}}catch(e){n=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(n)throw o}}return!this.options.legacy}},{key:"isSelectorWhitelisted",value:function(e){return!!(CSS_WHITELIST.includes(e)||this.options.whitelist&&this.options.whitelist.some(function(t){return t===e})||this.options.whitelistPatterns&&this.options.whitelistPatterns.some(function(t){return t.test(e)}))}}]),e}();module.exports=Purgecss; diff --git a/src/index.js b/src/index.js index 03dfe087..2107f9a3 100644 --- a/src/index.js +++ b/src/index.js @@ -406,21 +406,12 @@ class Purgecss { // non legacy extractors // pseudo class const unescapedSelector = selector.replace(/\\/g, '') - const isWhitelisted = this.isSelectorWhitelisted(selector) - - // As classes are read from left to right, we have to check the - // whitelist that passed the test and assert that children - // should be kept or not - if (isWhitelisted && this.hasSelectorKeepChildren(selector)) { - return true - } - if (unescapedSelector.startsWith(':')) continue if ( !( selectorsInContent.has(unescapedSelector) || CSS_WHITELIST.includes(unescapedSelector) || - isWhitelisted + this.isSelectorWhitelisted(unescapedSelector) ) ) { return false @@ -435,50 +426,13 @@ class Purgecss { * @param {string} selector css selector */ isSelectorWhitelisted(selector: string): boolean { - return this.getWhitelistedSelector(selector).hasOwnProperty('pattern') - } - - /** - * Return whitelisted selector configuration - * - * @param {string} selector - */ - getWhitelistedSelector(selector: string): Object { - if (this.options.whitelist) { - for (const item of this.options.whitelist) { - const isString = (typeof item === 'string') - const pattern = (isString) ? item : item.pattern - - // Assert the pattern match the given selector - if (pattern === selector) { - return (isString) ? { pattern : pattern } : item - } - } - } - - if (this.options.whitelistPatterns) { - for (const item of this.options.whitelistPatterns) { - const isRegExp = (item instanceof RegExp) - const pattern = (isRegExp) ? item : item.pattern - - // Assert the pattern match the given selector - if (pattern.test(selector)) { - return (isRegExp) ? { pattern : pattern } : item - } - } - } - - return {} - } - - /** - * Return corresponding whitelisted pattern if exists - * - * @param {string} selector - */ - hasSelectorKeepChildren(selector: string): Object { - const whitelist = this.getWhitelistedSelector(selector) - return (whitelist.hasOwnProperty('keepChildren')) ? whitelist.keepChildren : false + return !!( + CSS_WHITELIST.includes(selector) || + (this.options.whitelist && + this.options.whitelist.some((v: string) => v === selector)) || + (this.options.whitelistPatterns && + this.options.whitelistPatterns.some((v: RegExp) => v.test(selector))) + ) } } From 75729b8fc6da7646569173e578e710535f2232dc Mon Sep 17 00:00:00 2001 From: Cyril Mizzi Date: Wed, 14 Mar 2018 12:35:53 +0100 Subject: [PATCH 5/6] adds whitelistPatternsChildren option --- __tests__/purgecss.test.js | 40 +++++++++++++++++++ .../whitelist_patterns_children.css | 9 +++++ .../whitelist_patterns_children.html | 10 +++++ flow-typed/index.js | 1 + lib/purgecss.es.js | 2 +- lib/purgecss.js | 2 +- src/index.js | 30 +++++++++++++- 7 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 __tests__/test_examples/whitelist_patterns_children/whitelist_patterns_children.css create mode 100644 __tests__/test_examples/whitelist_patterns_children/whitelist_patterns_children.html diff --git a/__tests__/purgecss.test.js b/__tests__/purgecss.test.js index ad280f40..a617beb5 100644 --- a/__tests__/purgecss.test.js +++ b/__tests__/purgecss.test.js @@ -701,3 +701,43 @@ describe('purge methods with files and legacy extractor', () => { }) }) }) + +describe('whitelistPatternsChildren', () => { + let purgecssResult + beforeAll(() => { + purgecssResult = new Purgecss({ + content: [`${root}whitelist_patterns_children/whitelist_patterns_children.html`], + css: [`${root}whitelist_patterns_children/whitelist_patterns_children.css`], + legacy: false, + whitelistPatternsChildren: [/^card$/] + }).purge()[0].css + }) + + it('finds card class', () => { + expect(purgecssResult.includes('.card')).toBe(true) + }) + + it('finds card--title', () => { + expect(purgecssResult.includes('.title')).toBe(false) + }) + + it('finds card--content', () => { + expect(purgecssResult.includes('.card .content')).toBe(true) + }) + + it('finds btn', () => { + expect(purgecssResult.includes('.btn')).toBe(true) + }) + + it('finds btn yellow', () => { + expect(purgecssResult.includes('.card .btn .yellow')).toBe(true) + }) + + it('finds btn red', () => { + expect(purgecssResult.includes('.btn .red')).toBe(false) + }) + + it('excludes btn--green', () => { + expect(purgecssResult.includes('.btn__green')).toBe(false) + }) +}) diff --git a/__tests__/test_examples/whitelist_patterns_children/whitelist_patterns_children.css b/__tests__/test_examples/whitelist_patterns_children/whitelist_patterns_children.css new file mode 100644 index 00000000..830adf68 --- /dev/null +++ b/__tests__/test_examples/whitelist_patterns_children/whitelist_patterns_children.css @@ -0,0 +1,9 @@ +.card {} +.title {} +.card .content {} + +.btn {} +.btn .red {} +.btngreen {} + +.card .btn .yellow {} diff --git a/__tests__/test_examples/whitelist_patterns_children/whitelist_patterns_children.html b/__tests__/test_examples/whitelist_patterns_children/whitelist_patterns_children.html new file mode 100644 index 00000000..361d4d1e --- /dev/null +++ b/__tests__/test_examples/whitelist_patterns_children/whitelist_patterns_children.html @@ -0,0 +1,10 @@ + + +
+
+
+
+
+
+ + diff --git a/flow-typed/index.js b/flow-typed/index.js index 5e661283..8574510b 100644 --- a/flow-typed/index.js +++ b/flow-typed/index.js @@ -11,6 +11,7 @@ declare type Options = { extractors?: Array, whitelist?: Array, whitelistPatterns?: Array, + whitelistPatternsChildren?: Array, output?: string, stdout?: boolean, stdin?: boolean, diff --git a/lib/purgecss.es.js b/lib/purgecss.es.js index 859a217e..deeeca06 100644 --- a/lib/purgecss.es.js +++ b/lib/purgecss.es.js @@ -1 +1 @@ -import fs from"fs";import glob from"glob";import postcss from"postcss";import selectorParser from"postcss-selector-parser";function normalizeArray(e,t){for(var r=0,n=e.length-1;n>=0;n--){var o=e[n];"."===o?e.splice(n,1):".."===o?(e.splice(n,1),r++):r&&(e.splice(n,1),r--)}if(t)for(;r--;r)e.unshift("..");return e}var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,splitPath=function(e){return splitPathRe.exec(e).slice(1)};function resolve(){for(var e="",t=!1,r=arguments.length-1;r>=-1&&!t;r--){var n=r>=0?arguments[r]:"/";if("string"!=typeof n)throw new TypeError("Arguments to path.resolve must be strings");n&&(e=n+"/"+e,t="/"===n.charAt(0))}return e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"),(t?"/":"")+e||"."}function normalize(e){var t=isAbsolute(e),r="/"===substr(e,-1);return(e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"))||t||(e="."),e&&r&&(e+="/"),(t?"/":"")+e}function isAbsolute(e){return"/"===e.charAt(0)}function join(){return normalize(filter(Array.prototype.slice.call(arguments,0),function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e}).join("/"))}function relative(e,t){function r(e){for(var t=0;t=0&&""===e[r];r--);return t>r?[]:e.slice(t,r-t+1)}e=resolve(e).substr(1),t=resolve(t).substr(1);for(var n=r(e.split("/")),o=r(t.split("/")),i=Math.min(n.length,o.length),a=i,s=0;s1&&void 0!==arguments[1]?arguments[1]:[];return t.length?t.find(function(t){return t.extensions.find(function(t){return e.endsWith(t)})}).extractor:!0===this.options.legacy?LegacyExtractor:DefaultExtractor}},{key:"extractSelectors",value:function(e,t){var r=new Set,n=t.extract(e);if(null===n)throw new Error(ERROR_EXTRACTER_FAILED);return n.forEach(function(e){r.add(e)}),r.delete(""),r}},{key:"getSelectorsCss",value:function(e){var t=this;this.root.walk(function(r){return"rule"===r.type?t.evaluateRule(r,e):"atrule"===r.type?t.evaluateAtRule(r):void 0})}},{key:"evaluateRule",value:function(e,t){var r=this,n=e.prev();if(!this.isIgnoreAnnotation(n)){var o=!0;if(e.selector=selectorParser(function(e){e.walk(function(e){var n=[];if("selector"===e.type){if(e.parent&&":not"===e.parent.value&&"pseudo"===e.parent.type)return;var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.type,y=c.value;SELECTOR_STANDARD_TYPES.includes(f)&&void 0!==y?n.push(y):"tag"!==f||/[+]|(even)|(odd)|^from$|^to$|^\d/.test(y)||n.push(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}(o=r.shouldKeepSelector(t,n))||e.remove()}})}).processSync(e.selector),o){var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.prop,y=c.value;if(this.options.keyframes&&("animation"===f||"animation-name"===f)){var h=!0,p=!1,v=void 0;try{for(var d,E=y.split(" ")[Symbol.iterator]();!(h=(d=E.next()).done);h=!0){var R=d.value;this.usedAnimations.add(R)}}catch(e){p=!0,v=e}finally{try{!h&&E.return&&E.return()}finally{if(p)throw v}}}this.options.fontFace&&"font-family"===f&&this.usedFontFaces.add(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}}var m=e.parent;e.selector||e.remove(),this.isRuleEmpty(m)&&m.remove()}}},{key:"evaluateAtRule",value:function(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name){var t=!0,r=!1,n=void 0;try{for(var o,i=e.nodes[Symbol.iterator]();!(t=(o=i.next()).done);t=!0){var a=o.value,s=a.prop,l=a.value;"font-family"===s&&this.atRules.fontFace.push({name:l,node:e})}}catch(e){r=!0,n=e}finally{try{!t&&i.return&&i.return()}finally{if(r)throw n}}}else;}},{key:"isIgnoreAnnotation",value:function(e){return!(!e||"comment"!==e.type)&&e.text.includes(IGNORE_ANNOTATION)}},{key:"isRuleEmpty",value:function(e){return!!("decl"===e.type&&!e.value||"rule"===e.type&&!e.selector||e.nodes&&!e.nodes.length||"atrule"===e.type&&(!e.nodes&&!e.params||!e.params&&!e.nodes.length))}},{key:"shouldKeepSelector",value:function(e,t){var r=!0,n=!1,o=void 0;try{for(var i,a=t[Symbol.iterator]();!(r=(i=a.next()).done);r=!0){var s=i.value;if(this.options.legacy){var l=s.split(/[^a-z]/g),u=!1,c=!0,f=!1,y=void 0;try{for(var h,p=l[Symbol.iterator]();!(c=(h=p.next()).done);c=!0){var v=h.value;if(v){if(!e.has(v))break;u=!0}}}catch(e){f=!0,y=e}finally{try{!c&&p.return&&p.return()}finally{if(f)throw y}}if(u)return!0;if(e.has(s)||CSS_WHITELIST.includes(s)||this.isSelectorWhitelisted(s))return!0}else{var d=s.replace(/\\/g,"");if(d.startsWith(":"))continue;if(!(e.has(d)||CSS_WHITELIST.includes(d)||this.isSelectorWhitelisted(d)))return!1}}}catch(e){n=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(n)throw o}}return!this.options.legacy}},{key:"isSelectorWhitelisted",value:function(e){return!!(CSS_WHITELIST.includes(e)||this.options.whitelist&&this.options.whitelist.some(function(t){return t===e})||this.options.whitelistPatterns&&this.options.whitelistPatterns.some(function(t){return t.test(e)}))}}]),e}();export default Purgecss; +import fs from"fs";import glob from"glob";import postcss from"postcss";import selectorParser from"postcss-selector-parser";function normalizeArray(e,t){for(var r=0,n=e.length-1;n>=0;n--){var o=e[n];"."===o?e.splice(n,1):".."===o?(e.splice(n,1),r++):r&&(e.splice(n,1),r--)}if(t)for(;r--;r)e.unshift("..");return e}var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,splitPath=function(e){return splitPathRe.exec(e).slice(1)};function resolve(){for(var e="",t=!1,r=arguments.length-1;r>=-1&&!t;r--){var n=r>=0?arguments[r]:"/";if("string"!=typeof n)throw new TypeError("Arguments to path.resolve must be strings");n&&(e=n+"/"+e,t="/"===n.charAt(0))}return e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"),(t?"/":"")+e||"."}function normalize(e){var t=isAbsolute(e),r="/"===substr(e,-1);return(e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"))||t||(e="."),e&&r&&(e+="/"),(t?"/":"")+e}function isAbsolute(e){return"/"===e.charAt(0)}function join(){return normalize(filter(Array.prototype.slice.call(arguments,0),function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e}).join("/"))}function relative(e,t){function r(e){for(var t=0;t=0&&""===e[r];r--);return t>r?[]:e.slice(t,r-t+1)}e=resolve(e).substr(1),t=resolve(t).substr(1);for(var n=r(e.split("/")),o=r(t.split("/")),i=Math.min(n.length,o.length),a=i,s=0;s1&&void 0!==arguments[1]?arguments[1]:[];return t.length?t.find(function(t){return t.extensions.find(function(t){return e.endsWith(t)})}).extractor:!0===this.options.legacy?LegacyExtractor:DefaultExtractor}},{key:"extractSelectors",value:function(e,t){var r=new Set,n=t.extract(e);if(null===n)throw new Error(ERROR_EXTRACTER_FAILED);return n.forEach(function(e){r.add(e)}),r.delete(""),r}},{key:"getSelectorsCss",value:function(e){var t=this;this.root.walk(function(r){return"rule"===r.type?t.evaluateRule(r,e):"atrule"===r.type?t.evaluateAtRule(r):void 0})}},{key:"evaluateRule",value:function(e,t){var r=this,n=e.prev();if(!this.isIgnoreAnnotation(n)){var o=!0;if(e.selector=selectorParser(function(e){e.walk(function(e){var n=[];if("selector"===e.type){if(e.parent&&":not"===e.parent.value&&"pseudo"===e.parent.type)return;var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.type,y=c.value;SELECTOR_STANDARD_TYPES.includes(f)&&void 0!==y?n.push(y):"tag"!==f||/[+]|(even)|(odd)|^from$|^to$|^\d/.test(y)||n.push(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}(o=r.shouldKeepSelector(t,n))||e.remove()}})}).processSync(e.selector),o){var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.prop,y=c.value;if(this.options.keyframes&&("animation"===f||"animation-name"===f)){var h=!0,p=!1,v=void 0;try{for(var d,E=y.split(" ")[Symbol.iterator]();!(h=(d=E.next()).done);h=!0){var m=d.value;this.usedAnimations.add(m)}}catch(e){p=!0,v=e}finally{try{!h&&E.return&&E.return()}finally{if(p)throw v}}}this.options.fontFace&&"font-family"===f&&this.usedFontFaces.add(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}}var R=e.parent;e.selector||e.remove(),this.isRuleEmpty(R)&&R.remove()}}},{key:"evaluateAtRule",value:function(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name){var t=!0,r=!1,n=void 0;try{for(var o,i=e.nodes[Symbol.iterator]();!(t=(o=i.next()).done);t=!0){var a=o.value,s=a.prop,l=a.value;"font-family"===s&&this.atRules.fontFace.push({name:l,node:e})}}catch(e){r=!0,n=e}finally{try{!t&&i.return&&i.return()}finally{if(r)throw n}}}else;}},{key:"isIgnoreAnnotation",value:function(e){return!(!e||"comment"!==e.type)&&e.text.includes(IGNORE_ANNOTATION)}},{key:"isRuleEmpty",value:function(e){return!!("decl"===e.type&&!e.value||"rule"===e.type&&!e.selector||e.nodes&&!e.nodes.length||"atrule"===e.type&&(!e.nodes&&!e.params||!e.params&&!e.nodes.length))}},{key:"shouldKeepSelector",value:function(e,t){var r=!0,n=!1,o=void 0;try{for(var i,a=t[Symbol.iterator]();!(r=(i=a.next()).done);r=!0){var s=i.value;if(this.options.legacy){var l=s.split(/[^a-z]/g),u=!1,c=!0,f=!1,y=void 0;try{for(var h,p=l[Symbol.iterator]();!(c=(h=p.next()).done);c=!0){var v=h.value;if(this.isSelectorWhitelistedChildren(v)){u=!0;break}if(v){if(!e.has(v))break;u=!0}}}catch(e){f=!0,y=e}finally{try{!c&&p.return&&p.return()}finally{if(f)throw y}}if(u)return!0;if(e.has(s)||CSS_WHITELIST.includes(s)||this.isSelectorWhitelisted(s))return!0}else{var d=s.replace(/\\/g,"");if(d.startsWith(":"))continue;if(this.isSelectorWhitelistedChildren(d))return!0;if(!(e.has(d)||CSS_WHITELIST.includes(d)||this.isSelectorWhitelisted(d)))return!1}}}catch(e){n=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(n)throw o}}return!this.options.legacy}},{key:"isSelectorWhitelisted",value:function(e){return!!(CSS_WHITELIST.includes(e)||this.options.whitelist&&this.options.whitelist.some(function(t){return t===e})||this.options.whitelistPatterns&&this.options.whitelistPatterns.some(function(t){return t.test(e)}))}},{key:"isSelectorWhitelistedChildren",value:function(e){return!(!this.options.whitelistPatternsChildren||!this.options.whitelistPatternsChildren.some(function(t){return t.test(e)}))}}]),e}();export default Purgecss; diff --git a/lib/purgecss.js b/lib/purgecss.js index abc70c7a..071ce31d 100644 --- a/lib/purgecss.js +++ b/lib/purgecss.js @@ -1 +1 @@ -"use strict";function _interopDefault(e){return e&&"object"==typeof e&&"default"in e?e.default:e}var fs=_interopDefault(require("fs")),glob=_interopDefault(require("glob")),postcss=_interopDefault(require("postcss")),selectorParser=_interopDefault(require("postcss-selector-parser"));function normalizeArray(e,t){for(var r=0,n=e.length-1;n>=0;n--){var o=e[n];"."===o?e.splice(n,1):".."===o?(e.splice(n,1),r++):r&&(e.splice(n,1),r--)}if(t)for(;r--;r)e.unshift("..");return e}var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,splitPath=function(e){return splitPathRe.exec(e).slice(1)};function resolve(){for(var e="",t=!1,r=arguments.length-1;r>=-1&&!t;r--){var n=r>=0?arguments[r]:"/";if("string"!=typeof n)throw new TypeError("Arguments to path.resolve must be strings");n&&(e=n+"/"+e,t="/"===n.charAt(0))}return e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"),(t?"/":"")+e||"."}function normalize(e){var t=isAbsolute(e),r="/"===substr(e,-1);return(e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"))||t||(e="."),e&&r&&(e+="/"),(t?"/":"")+e}function isAbsolute(e){return"/"===e.charAt(0)}function join(){return normalize(filter(Array.prototype.slice.call(arguments,0),function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e}).join("/"))}function relative(e,t){function r(e){for(var t=0;t=0&&""===e[r];r--);return t>r?[]:e.slice(t,r-t+1)}e=resolve(e).substr(1),t=resolve(t).substr(1);for(var n=r(e.split("/")),o=r(t.split("/")),i=Math.min(n.length,o.length),a=i,s=0;s1&&void 0!==arguments[1]?arguments[1]:[];return t.length?t.find(function(t){return t.extensions.find(function(t){return e.endsWith(t)})}).extractor:!0===this.options.legacy?LegacyExtractor:DefaultExtractor}},{key:"extractSelectors",value:function(e,t){var r=new Set,n=t.extract(e);if(null===n)throw new Error(ERROR_EXTRACTER_FAILED);return n.forEach(function(e){r.add(e)}),r.delete(""),r}},{key:"getSelectorsCss",value:function(e){var t=this;this.root.walk(function(r){return"rule"===r.type?t.evaluateRule(r,e):"atrule"===r.type?t.evaluateAtRule(r):void 0})}},{key:"evaluateRule",value:function(e,t){var r=this,n=e.prev();if(!this.isIgnoreAnnotation(n)){var o=!0;if(e.selector=selectorParser(function(e){e.walk(function(e){var n=[];if("selector"===e.type){if(e.parent&&":not"===e.parent.value&&"pseudo"===e.parent.type)return;var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.type,y=c.value;SELECTOR_STANDARD_TYPES.includes(f)&&void 0!==y?n.push(y):"tag"!==f||/[+]|(even)|(odd)|^from$|^to$|^\d/.test(y)||n.push(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}(o=r.shouldKeepSelector(t,n))||e.remove()}})}).processSync(e.selector),o){var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.prop,y=c.value;if(this.options.keyframes&&("animation"===f||"animation-name"===f)){var h=!0,p=!1,v=void 0;try{for(var d,E=y.split(" ")[Symbol.iterator]();!(h=(d=E.next()).done);h=!0){var R=d.value;this.usedAnimations.add(R)}}catch(e){p=!0,v=e}finally{try{!h&&E.return&&E.return()}finally{if(p)throw v}}}this.options.fontFace&&"font-family"===f&&this.usedFontFaces.add(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}}var m=e.parent;e.selector||e.remove(),this.isRuleEmpty(m)&&m.remove()}}},{key:"evaluateAtRule",value:function(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name){var t=!0,r=!1,n=void 0;try{for(var o,i=e.nodes[Symbol.iterator]();!(t=(o=i.next()).done);t=!0){var a=o.value,s=a.prop,l=a.value;"font-family"===s&&this.atRules.fontFace.push({name:l,node:e})}}catch(e){r=!0,n=e}finally{try{!t&&i.return&&i.return()}finally{if(r)throw n}}}else;}},{key:"isIgnoreAnnotation",value:function(e){return!(!e||"comment"!==e.type)&&e.text.includes(IGNORE_ANNOTATION)}},{key:"isRuleEmpty",value:function(e){return!!("decl"===e.type&&!e.value||"rule"===e.type&&!e.selector||e.nodes&&!e.nodes.length||"atrule"===e.type&&(!e.nodes&&!e.params||!e.params&&!e.nodes.length))}},{key:"shouldKeepSelector",value:function(e,t){var r=!0,n=!1,o=void 0;try{for(var i,a=t[Symbol.iterator]();!(r=(i=a.next()).done);r=!0){var s=i.value;if(this.options.legacy){var l=s.split(/[^a-z]/g),u=!1,c=!0,f=!1,y=void 0;try{for(var h,p=l[Symbol.iterator]();!(c=(h=p.next()).done);c=!0){var v=h.value;if(v){if(!e.has(v))break;u=!0}}}catch(e){f=!0,y=e}finally{try{!c&&p.return&&p.return()}finally{if(f)throw y}}if(u)return!0;if(e.has(s)||CSS_WHITELIST.includes(s)||this.isSelectorWhitelisted(s))return!0}else{var d=s.replace(/\\/g,"");if(d.startsWith(":"))continue;if(!(e.has(d)||CSS_WHITELIST.includes(d)||this.isSelectorWhitelisted(d)))return!1}}}catch(e){n=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(n)throw o}}return!this.options.legacy}},{key:"isSelectorWhitelisted",value:function(e){return!!(CSS_WHITELIST.includes(e)||this.options.whitelist&&this.options.whitelist.some(function(t){return t===e})||this.options.whitelistPatterns&&this.options.whitelistPatterns.some(function(t){return t.test(e)}))}}]),e}();module.exports=Purgecss; +"use strict";function _interopDefault(e){return e&&"object"==typeof e&&"default"in e?e.default:e}var fs=_interopDefault(require("fs")),glob=_interopDefault(require("glob")),postcss=_interopDefault(require("postcss")),selectorParser=_interopDefault(require("postcss-selector-parser"));function normalizeArray(e,t){for(var r=0,n=e.length-1;n>=0;n--){var o=e[n];"."===o?e.splice(n,1):".."===o?(e.splice(n,1),r++):r&&(e.splice(n,1),r--)}if(t)for(;r--;r)e.unshift("..");return e}var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,splitPath=function(e){return splitPathRe.exec(e).slice(1)};function resolve(){for(var e="",t=!1,r=arguments.length-1;r>=-1&&!t;r--){var n=r>=0?arguments[r]:"/";if("string"!=typeof n)throw new TypeError("Arguments to path.resolve must be strings");n&&(e=n+"/"+e,t="/"===n.charAt(0))}return e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"),(t?"/":"")+e||"."}function normalize(e){var t=isAbsolute(e),r="/"===substr(e,-1);return(e=normalizeArray(filter(e.split("/"),function(e){return!!e}),!t).join("/"))||t||(e="."),e&&r&&(e+="/"),(t?"/":"")+e}function isAbsolute(e){return"/"===e.charAt(0)}function join(){return normalize(filter(Array.prototype.slice.call(arguments,0),function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e}).join("/"))}function relative(e,t){function r(e){for(var t=0;t=0&&""===e[r];r--);return t>r?[]:e.slice(t,r-t+1)}e=resolve(e).substr(1),t=resolve(t).substr(1);for(var n=r(e.split("/")),o=r(t.split("/")),i=Math.min(n.length,o.length),a=i,s=0;s1&&void 0!==arguments[1]?arguments[1]:[];return t.length?t.find(function(t){return t.extensions.find(function(t){return e.endsWith(t)})}).extractor:!0===this.options.legacy?LegacyExtractor:DefaultExtractor}},{key:"extractSelectors",value:function(e,t){var r=new Set,n=t.extract(e);if(null===n)throw new Error(ERROR_EXTRACTER_FAILED);return n.forEach(function(e){r.add(e)}),r.delete(""),r}},{key:"getSelectorsCss",value:function(e){var t=this;this.root.walk(function(r){return"rule"===r.type?t.evaluateRule(r,e):"atrule"===r.type?t.evaluateAtRule(r):void 0})}},{key:"evaluateRule",value:function(e,t){var r=this,n=e.prev();if(!this.isIgnoreAnnotation(n)){var o=!0;if(e.selector=selectorParser(function(e){e.walk(function(e){var n=[];if("selector"===e.type){if(e.parent&&":not"===e.parent.value&&"pseudo"===e.parent.type)return;var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.type,y=c.value;SELECTOR_STANDARD_TYPES.includes(f)&&void 0!==y?n.push(y):"tag"!==f||/[+]|(even)|(odd)|^from$|^to$|^\d/.test(y)||n.push(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}(o=r.shouldKeepSelector(t,n))||e.remove()}})}).processSync(e.selector),o){var i=!0,a=!1,s=void 0;try{for(var l,u=e.nodes[Symbol.iterator]();!(i=(l=u.next()).done);i=!0){var c=l.value,f=c.prop,y=c.value;if(this.options.keyframes&&("animation"===f||"animation-name"===f)){var h=!0,p=!1,v=void 0;try{for(var d,E=y.split(" ")[Symbol.iterator]();!(h=(d=E.next()).done);h=!0){var R=d.value;this.usedAnimations.add(R)}}catch(e){p=!0,v=e}finally{try{!h&&E.return&&E.return()}finally{if(p)throw v}}}this.options.fontFace&&"font-family"===f&&this.usedFontFaces.add(y)}}catch(e){a=!0,s=e}finally{try{!i&&u.return&&u.return()}finally{if(a)throw s}}}var m=e.parent;e.selector||e.remove(),this.isRuleEmpty(m)&&m.remove()}}},{key:"evaluateAtRule",value:function(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name){var t=!0,r=!1,n=void 0;try{for(var o,i=e.nodes[Symbol.iterator]();!(t=(o=i.next()).done);t=!0){var a=o.value,s=a.prop,l=a.value;"font-family"===s&&this.atRules.fontFace.push({name:l,node:e})}}catch(e){r=!0,n=e}finally{try{!t&&i.return&&i.return()}finally{if(r)throw n}}}else;}},{key:"isIgnoreAnnotation",value:function(e){return!(!e||"comment"!==e.type)&&e.text.includes(IGNORE_ANNOTATION)}},{key:"isRuleEmpty",value:function(e){return!!("decl"===e.type&&!e.value||"rule"===e.type&&!e.selector||e.nodes&&!e.nodes.length||"atrule"===e.type&&(!e.nodes&&!e.params||!e.params&&!e.nodes.length))}},{key:"shouldKeepSelector",value:function(e,t){var r=!0,n=!1,o=void 0;try{for(var i,a=t[Symbol.iterator]();!(r=(i=a.next()).done);r=!0){var s=i.value;if(this.options.legacy){var l=s.split(/[^a-z]/g),u=!1,c=!0,f=!1,y=void 0;try{for(var h,p=l[Symbol.iterator]();!(c=(h=p.next()).done);c=!0){var v=h.value;if(this.isSelectorWhitelistedChildren(v)){u=!0;break}if(v){if(!e.has(v))break;u=!0}}}catch(e){f=!0,y=e}finally{try{!c&&p.return&&p.return()}finally{if(f)throw y}}if(u)return!0;if(e.has(s)||CSS_WHITELIST.includes(s)||this.isSelectorWhitelisted(s))return!0}else{var d=s.replace(/\\/g,"");if(d.startsWith(":"))continue;if(this.isSelectorWhitelistedChildren(d))return!0;if(!(e.has(d)||CSS_WHITELIST.includes(d)||this.isSelectorWhitelisted(d)))return!1}}}catch(e){n=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(n)throw o}}return!this.options.legacy}},{key:"isSelectorWhitelisted",value:function(e){return!!(CSS_WHITELIST.includes(e)||this.options.whitelist&&this.options.whitelist.some(function(t){return t===e})||this.options.whitelistPatterns&&this.options.whitelistPatterns.some(function(t){return t.test(e)}))}},{key:"isSelectorWhitelistedChildren",value:function(e){return!(!this.options.whitelistPatternsChildren||!this.options.whitelistPatternsChildren.some(function(t){return t.test(e)}))}}]),e}();module.exports=Purgecss; diff --git a/src/index.js b/src/index.js index 2107f9a3..bfc91541 100644 --- a/src/index.js +++ b/src/index.js @@ -391,6 +391,11 @@ class Purgecss { const sels = selector.split(/[^a-z]/g) let keepSelector = false for (let sel of sels) { + if (this.isSelectorWhitelistedChildren(sel)) { + keepSelector = true + break + } + if (!sel) continue if (!selectorsInContent.has(sel)) break keepSelector = true @@ -406,7 +411,17 @@ class Purgecss { // non legacy extractors // pseudo class const unescapedSelector = selector.replace(/\\/g, '') - if (unescapedSelector.startsWith(':')) continue + + if (unescapedSelector.startsWith(':')) { + continue + } + + // If the selector is whitelisted with children keep, simply + // returns true to keep all children selectors + if (this.isSelectorWhitelistedChildren(unescapedSelector)) { + return true + } + if ( !( selectorsInContent.has(unescapedSelector) || @@ -434,6 +449,19 @@ class Purgecss { this.options.whitelistPatterns.some((v: RegExp) => v.test(selector))) ) } + + /** + * Check if the selector is whitelisted by the whitelistPatternsChildren + * options element + * + * @param {string} selector + */ + isSelectorWhitelistedChildren(selector: string): boolean { + return !!( + this.options.whitelistPatternsChildren && + this.options.whitelistPatternsChildren.some((v: RegExp) => v.test(selector)) + ) + } } export default Purgecss From 772eccfd01fe4f5666ad80d9ccce68999adb9c31 Mon Sep 17 00:00:00 2001 From: Ffloriel Date: Tue, 20 Mar 2018 23:16:19 +0000 Subject: [PATCH 6/6] typescript definition add whitelistPatternsChildren to typescript definition file --- lib/purgecss.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/purgecss.d.ts b/lib/purgecss.d.ts index c81560de..fae3cad5 100644 --- a/lib/purgecss.d.ts +++ b/lib/purgecss.d.ts @@ -40,6 +40,7 @@ declare namespace Purgecss { extractors?: Array whitelist?: Array whitelistPatterns?: Array + whitelistPatternsChildren?: Array output?: string stdout?: boolean stdin?: boolean