purgecss 4.1.3 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import*as e from"fs";import t from"glob";import s from"path";import*as r from"postcss";import i from"postcss-selector-parser";import{promisify as o}from"util";function n(e,t){t&&t.forEach(e.add,e)}class a{constructor(e){this.undetermined=new Set,this.attrNames=new Set,this.attrValues=new Set,this.classes=new Set,this.ids=new Set,this.tags=new Set,this.merge(e)}merge(e){return Array.isArray(e)?n(this.undetermined,e):e instanceof a?(n(this.undetermined,e.undetermined),n(this.attrNames,e.attrNames),n(this.attrValues,e.attrValues),n(this.classes,e.classes),n(this.ids,e.ids),n(this.tags,e.tags)):(n(this.undetermined,e.undetermined),e.attributes&&(n(this.attrNames,e.attributes.names),n(this.attrValues,e.attributes.values)),n(this.classes,e.classes),n(this.ids,e.ids),n(this.tags,e.tags)),this}hasAttrName(e){return this.attrNames.has(e)||this.undetermined.has(e)}someAttrValue(e){for(const t of this.attrValues)if(e(t))return!0;for(const t of this.undetermined)if(e(t))return!0;return!1}hasAttrPrefix(e){return this.someAttrValue((t=>t.startsWith(e)))}hasAttrSuffix(e){return this.someAttrValue((t=>t.endsWith(e)))}hasAttrSubstr(e){return e.trim().split(" ").every((e=>this.someAttrValue((t=>t.includes(e)))))}hasAttrValue(e){return this.attrValues.has(e)||this.undetermined.has(e)}hasClass(e){return this.classes.has(e)||this.undetermined.has(e)}hasId(e){return this.ids.has(e)||this.undetermined.has(e)}hasTag(e){return this.tags.has(e)||this.undetermined.has(e)}}const c=["*",":root",":after",":before"],l={css:[],content:[],defaultExtractor:e=>e.match(/[A-Za-z0-9_-]+/g)||[],extractors:[],fontFace:!1,keyframes:!1,rejected:!1,rejectedCss:!1,stdin:!1,stdout:!1,variables:!1,safelist:{standard:[],deep:[],greedy:[],variables:[],keyframes:[]},blocklist:[],skippedContentGlobs:[],dynamicAttributes:[]};function u(e,t){const s=[];return e.replace(t,(function(){const t=arguments,r=Array.prototype.slice.call(t,0,-2);return r.input=t[t.length-1],r.index=t[t.length-2],s.push(r),e})),s}class h{constructor(e){this.nodes=[],this.isUsed=!1,this.value=e}}class d{constructor(){this.nodes=new Map,this.usedVariables=new Set,this.safelist=[]}addVariable(e){const{prop:t}=e;if(this.nodes.has(t)){const s=new h(e),r=this.nodes.get(t)||[];this.nodes.set(t,[...r,s])}else{const s=new h(e);this.nodes.set(t,[s])}}addVariableUsage(e,t){const{prop:s}=e,r=this.nodes.get(s);for(const e of t){const t=e[1];if(this.nodes.has(t)){const e=this.nodes.get(t);null==r||r.forEach((t=>{null==e||e.forEach((e=>t.nodes.push(e)))}))}}}addVariableUsageInProperties(e){for(const t of e){const e=t[1];this.usedVariables.add(e)}}setAsUsed(e){const t=this.nodes.get(e);if(t){const e=[...t];for(;0!==e.length;){const t=e.pop();t&&!t.isUsed&&(t.isUsed=!0,e.push(...t.nodes))}}}removeUnused(){for(const e of this.usedVariables){const t=this.nodes.get(e);if(t)for(const e of t){u(e.value.value,/var\((.+?)[,)]/g).forEach((e=>{this.usedVariables.has(e[1])||this.usedVariables.add(e[1])}))}}for(const e of this.usedVariables)this.setAsUsed(e);for(const[e,t]of this.nodes)for(const s of t)s.isUsed||this.isVariablesSafelisted(e)||s.value.remove()}isVariablesSafelisted(e){return this.safelist.some((t=>"string"==typeof t?t===e:t.test(e)))}}const f={access:o(e.access),readFile:o(e.readFile)};function p(e=[]){return Array.isArray(e)?{...l.safelist,standard:e}:{...l.safelist,...e}}async function m(e="purgecss.config.js"){let t;try{const r=s.resolve(process.cwd(),e);t=await import(r)}catch(e){throw new Error(`Error loading the config file ${e.message}`)}return{...l,...t,safelist:p(t.safelist)}}async function g(e,t){return new a(await t(e))}function v(e,t){switch(t){case"next":return e.text.includes("purgecss ignore");case"start":return e.text.includes("purgecss start ignore");case"end":return e.text.includes("purgecss end ignore")}}function y(...e){const t=new a([]);return e.forEach(t.merge,t),t}function S(e){return e.replace(/(^["'])|(["']$)/g,"")}function b(e,t){if(!t.hasAttrName(e.attribute))return!1;if(void 0===e.value)return!0;switch(e.operator){case"$=":return t.hasAttrSuffix(e.value);case"~=":case"*=":return t.hasAttrSubstr(e.value);case"=":return t.hasAttrValue(e.value);case"|=":case"^=":return t.hasAttrPrefix(e.value);default:return!0}}function w(e,t){return t.hasId(e.value)}function A(e,t){return t.hasTag(e.value)}function F(e){return"atrule"===(null==e?void 0:e.type)}function V(e){return"rule"===(null==e?void 0:e.type)}class k{constructor(){this.ignore=!1,this.atRules={fontFace:[],keyframes:[]},this.usedAnimations=new Set,this.usedFontFaces=new Set,this.selectorsRemoved=new Set,this.removedNodes=[],this.variablesStructure=new d,this.options=l}collectDeclarationsData(e){const{prop:t,value:s}=e;if(this.options.variables){const r=u(s,/var\((.+?)[,)]/g);t.startsWith("--")?(this.variablesStructure.addVariable(e),r.length>0&&this.variablesStructure.addVariableUsage(e,r)):r.length>0&&this.variablesStructure.addVariableUsageInProperties(r)}if(!this.options.keyframes||"animation"!==t&&"animation-name"!==t)if(this.options.fontFace){if("font-family"===t)for(const e of s.split(",")){const t=S(e.trim());this.usedFontFaces.add(t)}}else;else for(const e of s.split(/[\s,]+/))this.usedAnimations.add(e)}getFileExtractor(e,t){const s=t.find((t=>t.extensions.find((t=>e.endsWith(t)))));return void 0===s?this.options.defaultExtractor:s.extractor}async extractSelectorsFromFiles(s,r){const i=new a([]);for(const o of s){let s=[];try{await f.access(o,e.constants.F_OK),s.push(o)}catch(e){s=t.sync(o,{nodir:!0,ignore:this.options.skippedContentGlobs})}for(const e of s){const t=await f.readFile(e,"utf-8"),s=this.getFileExtractor(e,r),o=await g(t,s);i.merge(o)}}return i}async extractSelectorsFromString(e,t){const s=new a([]);for(const{raw:r,extension:i}of e){const e=this.getFileExtractor(`.${i}`,t),o=await g(r,e);s.merge(o)}return s}evaluateAtRule(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name&&e.nodes)for(const t of e.nodes)"decl"===t.type&&"font-family"===t.prop&&this.atRules.fontFace.push({name:S(t.value),node:e})}evaluateRule(e,t){if(this.ignore)return;const s=e.prev();if(function(e){return"comment"===(null==e?void 0:e.type)}(s)&&v(s,"next"))return void s.remove();if(e.parent&&F(e.parent)&&e.parent.name.endsWith("keyframes"))return;if(!V(e))return;if(function(e){let t=!1;return e.walkComments((e=>{e&&"comment"===e.type&&e.text.includes("purgecss ignore current")&&(t=!0,e.remove())})),t}(e))return;let r=!0;const o=[];if(e.selector=i((e=>{e.walk((e=>{"selector"===e.type&&(r=this.shouldKeepSelector(e,t),r||(this.options.rejected&&this.selectorsRemoved.add(e.toString()),this.options.rejectedCss&&o.push(e.toString()),e.remove()))}))})).processSync(e.selector),r&&void 0!==e.nodes)for(const t of e.nodes)"decl"===t.type&&this.collectDeclarationsData(t);const n=e.parent;if(e.selector||e.remove(),function(e){return!!(V(e)&&!e.selector||(null==e?void 0:e.nodes)&&!e.nodes.length||F(e)&&(!e.nodes&&!e.params||!e.params&&e.nodes&&!e.nodes.length))}(n)&&(null==n||n.remove()),this.options.rejectedCss&&o.length>0){const t=e.clone(),s=null==n?void 0:n.clone().removeAll().append(t);t.selectors=o;const r=s||t;this.removedNodes.push(r)}}async getPurgedCSS(e,s){const i=[],o=[];for(const s of e)"string"==typeof s?o.push(...t.sync(s,{nodir:!0,ignore:this.options.skippedContentGlobs})):o.push(s);for(const e of o){const t="string"==typeof e?this.options.stdin?e:await f.readFile(e,"utf-8"):e.raw,o=r.parse(t);this.walkThroughCSS(o,s),this.options.fontFace&&this.removeUnusedFontFaces(),this.options.keyframes&&this.removeUnusedKeyframes(),this.options.variables&&this.removeUnusedCSSVariables();const n={css:o.toString(),file:"string"==typeof e?e:e.name};this.options.rejected&&(n.rejected=Array.from(this.selectorsRemoved),this.selectorsRemoved.clear()),this.options.rejectedCss&&(n.rejectedCss=r.root({nodes:this.removedNodes}).toString()),i.push(n)}return i}isKeyframesSafelisted(e){return this.options.safelist.keyframes.some((t=>"string"==typeof t?t===e:t.test(e)))}isSelectorBlocklisted(e){return this.options.blocklist.some((t=>"string"==typeof t?t===e:t.test(e)))}isSelectorSafelisted(e){const t=this.options.safelist.standard.some((t=>"string"==typeof t?t===e:t.test(e))),s=/^::.*/.test(e);return c.includes(e)||s||t}isSelectorSafelistedDeep(e){return this.options.safelist.deep.some((t=>t.test(e)))}isSelectorSafelistedGreedy(e){return this.options.safelist.greedy.some((t=>t.test(e)))}async purge(e){this.options="object"!=typeof e?await m(e):{...l,...e,safelist:p(e.safelist)};const{content:t,css:s,extractors:r,safelist:i}=this.options;this.options.variables&&(this.variablesStructure.safelist=i.variables||[]);const o=t.filter((e=>"string"==typeof e)),n=t.filter((e=>"object"==typeof e)),a=await this.extractSelectorsFromFiles(o,r),c=await this.extractSelectorsFromString(n,r);return this.getPurgedCSS(s,y(a,c))}removeUnusedCSSVariables(){this.variablesStructure.removeUnused()}removeUnusedFontFaces(){for(const{name:e,node:t}of this.atRules.fontFace)this.usedFontFaces.has(e)||t.remove()}removeUnusedKeyframes(){for(const e of this.atRules.keyframes)this.usedAnimations.has(e.params)||this.isKeyframesSafelisted(e.params)||e.remove()}getSelectorValue(e){return"attribute"===e.type&&e.attribute||e.value}shouldKeepSelector(e,t){if(function(e){return e.parent&&"pseudo"===e.parent.type&&e.parent.value.startsWith(":")||!1}(e))return!0;if(this.options.safelist.greedy.length>0){if(e.nodes.map(this.getSelectorValue).some((e=>e&&this.isSelectorSafelistedGreedy(e))))return!0}let s=!1;for(const i of e.nodes){const e=this.getSelectorValue(i);if(e&&this.isSelectorSafelistedDeep(e))return!0;if(e&&(c.includes(e)||this.isSelectorSafelisted(e)))s=!0;else{if(e&&this.isSelectorBlocklisted(e))return!1;switch(i.type){case"attribute":s=!![...this.options.dynamicAttributes,"value","checked","selected","open"].includes(i.attribute)||b(i,t);break;case"class":r=i,s=t.hasClass(r.value);break;case"id":s=w(i,t);break;case"tag":s=A(i,t);break;default:continue}if(!s)return!1}}var r;return s}walkThroughCSS(e,t){e.walk((e=>"rule"===e.type?this.evaluateRule(e,t):"atrule"===e.type?this.evaluateAtRule(e):void("comment"===e.type&&(v(e,"start")?(this.ignore=!0,e.remove()):v(e,"end")&&(this.ignore=!1,e.remove())))))}}export{k as PurgeCSS,k as default,l as defaultOptions,y as mergeExtractorSelectors,m as setOptions,p as standardizeSafelist};
1
+ import*as e from"fs";import*as t from"glob";import*as s from"path";import*as r from"postcss";import o from"postcss-selector-parser";import{promisify as i}from"util";function a(e,t){t&&t.forEach(e.add,e)}class ExtractorResultSets{constructor(e){this.undetermined=new Set,this.attrNames=new Set,this.attrValues=new Set,this.classes=new Set,this.ids=new Set,this.tags=new Set,this.merge(e)}merge(e){return Array.isArray(e)?a(this.undetermined,e):e instanceof ExtractorResultSets?(a(this.undetermined,e.undetermined),a(this.attrNames,e.attrNames),a(this.attrValues,e.attrValues),a(this.classes,e.classes),a(this.ids,e.ids),a(this.tags,e.tags)):(a(this.undetermined,e.undetermined),e.attributes&&(a(this.attrNames,e.attributes.names),a(this.attrValues,e.attributes.values)),a(this.classes,e.classes),a(this.ids,e.ids),a(this.tags,e.tags)),this}hasAttrName(e){return this.attrNames.has(e)||this.undetermined.has(e)}someAttrValue(e){for(const t of this.attrValues)if(e(t))return!0;for(const t of this.undetermined)if(e(t))return!0;return!1}hasAttrPrefix(e){return this.someAttrValue((t=>t.startsWith(e)))}hasAttrSuffix(e){return this.someAttrValue((t=>t.endsWith(e)))}hasAttrSubstr(e){return e.trim().split(" ").every((e=>this.someAttrValue((t=>t.includes(e)))))}hasAttrValue(e){return this.attrValues.has(e)||this.undetermined.has(e)}hasClass(e){return this.classes.has(e)||this.undetermined.has(e)}hasId(e){return this.ids.has(e)||this.undetermined.has(e)}hasTag(e){return this.tags.has(e)||this.undetermined.has(e)}}const n=["*",":root",":after",":before"],c={css:[],content:[],defaultExtractor:e=>e.match(/[A-Za-z0-9_-]+/g)||[],extractors:[],fontFace:!1,keyframes:!1,rejected:!1,rejectedCss:!1,sourceMap:!1,stdin:!1,stdout:!1,variables:!1,safelist:{standard:[],deep:[],greedy:[],variables:[],keyframes:[]},blocklist:[],skippedContentGlobs:[],dynamicAttributes:[]};function l(e,t){const s=[];return e.replace(t,(function(){const t=arguments,r=Array.prototype.slice.call(t,0,-2);return r.input=t[t.length-1],r.index=t[t.length-2],s.push(r),e})),s}class VariableNode{constructor(e){this.nodes=[],this.isUsed=!1,this.value=e}}class VariablesStructure{constructor(){this.nodes=new Map,this.usedVariables=new Set,this.safelist=[]}addVariable(e){const{prop:t}=e;if(this.nodes.has(t)){const s=new VariableNode(e),r=this.nodes.get(t)||[];this.nodes.set(t,[...r,s])}else{const s=new VariableNode(e);this.nodes.set(t,[s])}}addVariableUsage(e,t){const{prop:s}=e,r=this.nodes.get(s);for(const e of t){const t=e[1];if(this.nodes.has(t)){const e=this.nodes.get(t);null==r||r.forEach((t=>{null==e||e.forEach((e=>t.nodes.push(e)))}))}}}addVariableUsageInProperties(e){for(const t of e){const e=t[1];this.usedVariables.add(e)}}setAsUsed(e){const t=this.nodes.get(e);if(t){const e=[...t];for(;0!==e.length;){const t=e.pop();t&&!t.isUsed&&(t.isUsed=!0,e.push(...t.nodes))}}}removeUnused(){for(const e of this.usedVariables){const t=this.nodes.get(e);if(t)for(const e of t){l(e.value.value,/var\((.+?)[,)]/g).forEach((e=>{this.usedVariables.has(e[1])||this.usedVariables.add(e[1])}))}}for(const e of this.usedVariables)this.setAsUsed(e);for(const[e,t]of this.nodes)for(const s of t)s.isUsed||this.isVariablesSafelisted(e)||s.value.remove()}isVariablesSafelisted(e){return this.safelist.some((t=>"string"==typeof t?t===e:t.test(e)))}}const u={access:i(e.access),readFile:i(e.readFile)};function d(e=[]){return Array.isArray(e)?{...c.safelist,standard:e}:{...c.safelist,...e}}async function h(e="purgecss.config.js"){let t;try{const r=s.resolve(process.cwd(),e);t=await import(r)}catch(e){if(e instanceof Error)throw new Error(`Error loading the config file ${e.message}`);throw new Error}return{...c,...t,safelist:d(t.safelist)}}async function f(e,t){return new ExtractorResultSets(await t(e))}function p(e,t){switch(t){case"next":return e.text.includes("purgecss ignore");case"start":return e.text.includes("purgecss start ignore");case"end":return e.text.includes("purgecss end ignore")}}function m(...e){const t=new ExtractorResultSets([]);return e.forEach(t.merge,t),t}function g(e){return e.replace(/(^["'])|(["']$)/g,"")}function v(e,t){if(!t.hasAttrName(e.attribute))return!1;if(void 0===e.value)return!0;switch(e.operator){case"$=":return t.hasAttrSuffix(e.value);case"~=":case"*=":return t.hasAttrSubstr(e.value);case"=":return t.hasAttrValue(e.value);case"|=":case"^=":return t.hasAttrPrefix(e.value);default:return!0}}function S(e,t){return t.hasId(e.value)}function y(e,t){return t.hasTag(e.value)}function b(e){return"atrule"===(null==e?void 0:e.type)}function w(e){return"rule"===(null==e?void 0:e.type)}class PurgeCSS{constructor(){this.ignore=!1,this.atRules={fontFace:[],keyframes:[]},this.usedAnimations=new Set,this.usedFontFaces=new Set,this.selectorsRemoved=new Set,this.removedNodes=[],this.variablesStructure=new VariablesStructure,this.options=c}collectDeclarationsData(e){const{prop:t,value:s}=e;if(this.options.variables){const r=l(s,/var\((.+?)[,)]/g);t.startsWith("--")?(this.variablesStructure.addVariable(e),r.length>0&&this.variablesStructure.addVariableUsage(e,r)):r.length>0&&this.variablesStructure.addVariableUsageInProperties(r)}if(!this.options.keyframes||"animation"!==t&&"animation-name"!==t)if(this.options.fontFace){if("font-family"===t)for(const e of s.split(",")){const t=g(e.trim());this.usedFontFaces.add(t)}}else;else for(const e of s.split(/[\s,]+/))this.usedAnimations.add(e)}getFileExtractor(e,t){const s=t.find((t=>t.extensions.find((t=>e.endsWith(t)))));return void 0===s?this.options.defaultExtractor:s.extractor}async extractSelectorsFromFiles(s,r){const o=new ExtractorResultSets([]);for(const i of s){let s=[];try{await u.access(i,e.constants.F_OK),s.push(i)}catch(e){s=t.sync(i,{nodir:!0,ignore:this.options.skippedContentGlobs})}for(const e of s){const t=await u.readFile(e,"utf-8"),s=this.getFileExtractor(e,r),i=await f(t,s);o.merge(i)}}return o}async extractSelectorsFromString(e,t){const s=new ExtractorResultSets([]);for(const{raw:r,extension:o}of e){const e=this.getFileExtractor(`.${o}`,t),i=await f(r,e);s.merge(i)}return s}evaluateAtRule(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name&&e.nodes)for(const t of e.nodes)"decl"===t.type&&"font-family"===t.prop&&this.atRules.fontFace.push({name:g(t.value),node:e})}evaluateRule(e,t){if(this.ignore)return;const s=e.prev();if(function(e){return"comment"===(null==e?void 0:e.type)}(s)&&p(s,"next"))return void s.remove();if(e.parent&&b(e.parent)&&e.parent.name.endsWith("keyframes"))return;if(!w(e))return;if(function(e){let t=!1;return e.walkComments((e=>{e&&"comment"===e.type&&e.text.includes("purgecss ignore current")&&(t=!0,e.remove())})),t}(e))return;let r=!0;const i=[];if(e.selector=o((e=>{e.walk((e=>{"selector"===e.type&&(r=this.shouldKeepSelector(e,t),r||(this.options.rejected&&this.selectorsRemoved.add(e.toString()),this.options.rejectedCss&&i.push(e.toString()),e.remove()))}))})).processSync(e.selector),r&&void 0!==e.nodes)for(const t of e.nodes)"decl"===t.type&&this.collectDeclarationsData(t);const a=e.parent;if(e.selector||e.remove(),function(e){return!!(w(e)&&!e.selector||(null==e?void 0:e.nodes)&&!e.nodes.length||b(e)&&(!e.nodes&&!e.params||!e.params&&e.nodes&&!e.nodes.length))}(a)&&(null==a||a.remove()),this.options.rejectedCss&&i.length>0){const t=e.clone(),s=null==a?void 0:a.clone().removeAll().append(t);t.selectors=i;const r=s||t;this.removedNodes.push(r)}}async getPurgedCSS(e,s){var o;const i=[],a=[];for(const s of e)"string"==typeof s?a.push(...t.sync(s,{nodir:!0,ignore:this.options.skippedContentGlobs})):a.push(s);for(const e of a){const t="string"==typeof e?this.options.stdin?e:await u.readFile(e,"utf-8"):e.raw,a="string"==typeof e&&!this.options.stdin,n=r.parse(t,{from:a?e:void 0});this.walkThroughCSS(n,s),this.options.fontFace&&this.removeUnusedFontFaces(),this.options.keyframes&&this.removeUnusedKeyframes(),this.options.variables&&this.removeUnusedCSSVariables();const c=n.toResult({map:this.options.sourceMap,to:"object"==typeof this.options.sourceMap?this.options.sourceMap.to:void 0}),l={css:c.toString(),file:"string"==typeof e?e:e.name};this.options.sourceMap&&(l.sourceMap=null===(o=c.map)||void 0===o?void 0:o.toString()),this.options.rejected&&(l.rejected=Array.from(this.selectorsRemoved),this.selectorsRemoved.clear()),this.options.rejectedCss&&(l.rejectedCss=r.root({nodes:this.removedNodes}).toString()),i.push(l)}return i}isKeyframesSafelisted(e){return this.options.safelist.keyframes.some((t=>"string"==typeof t?t===e:t.test(e)))}isSelectorBlocklisted(e){return this.options.blocklist.some((t=>"string"==typeof t?t===e:t.test(e)))}isSelectorSafelisted(e){const t=this.options.safelist.standard.some((t=>"string"==typeof t?t===e:t.test(e))),s=/^::.*/.test(e);return n.includes(e)||s||t}isSelectorSafelistedDeep(e){return this.options.safelist.deep.some((t=>t.test(e)))}isSelectorSafelistedGreedy(e){return this.options.safelist.greedy.some((t=>t.test(e)))}async purge(e){this.options="object"!=typeof e?await h(e):{...c,...e,safelist:d(e.safelist)};const{content:t,css:s,extractors:r,safelist:o}=this.options;this.options.variables&&(this.variablesStructure.safelist=o.variables||[]);const i=t.filter((e=>"string"==typeof e)),a=t.filter((e=>"object"==typeof e)),n=await this.extractSelectorsFromFiles(i,r),l=await this.extractSelectorsFromString(a,r);return this.getPurgedCSS(s,m(n,l))}removeUnusedCSSVariables(){this.variablesStructure.removeUnused()}removeUnusedFontFaces(){for(const{name:e,node:t}of this.atRules.fontFace)this.usedFontFaces.has(e)||t.remove()}removeUnusedKeyframes(){for(const e of this.atRules.keyframes)this.usedAnimations.has(e.params)||this.isKeyframesSafelisted(e.params)||e.remove()}getSelectorValue(e){return"attribute"===e.type&&e.attribute||e.value}shouldKeepSelector(e,t){if(function(e){return e.parent&&"pseudo"===e.parent.type&&e.parent.value.startsWith(":")||!1}(e))return!0;if(this.options.safelist.greedy.length>0){if(e.nodes.map(this.getSelectorValue).some((e=>e&&this.isSelectorSafelistedGreedy(e))))return!0}let s=!1;for(const o of e.nodes){const e=this.getSelectorValue(o);if(e&&this.isSelectorSafelistedDeep(e))return!0;if(e&&(n.includes(e)||this.isSelectorSafelisted(e)))s=!0;else{if(e&&this.isSelectorBlocklisted(e))return!1;switch(o.type){case"attribute":s=!![...this.options.dynamicAttributes,"value","checked","selected","open"].includes(o.attribute)||v(o,t);break;case"class":r=o,s=t.hasClass(r.value);break;case"id":s=S(o,t);break;case"tag":s=y(o,t);break;default:continue}if(!s)return!1}}var r;return s}walkThroughCSS(e,t){e.walk((e=>"rule"===e.type?this.evaluateRule(e,t):"atrule"===e.type?this.evaluateAtRule(e):void("comment"===e.type&&(p(e,"start")?(this.ignore=!0,e.remove()):p(e,"end")&&(this.ignore=!1,e.remove())))))}}export{ExtractorResultSets,PurgeCSS,c as defaultOptions,m as mergeExtractorSelectors,h as setOptions,d as standardizeSafelist};
package/lib/purgecss.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("fs"),t=require("glob"),s=require("path"),r=require("postcss"),i=require("postcss-selector-parser"),n=require("util");function o(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function a(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(s){if("default"!==s){var r=Object.getOwnPropertyDescriptor(e,s);Object.defineProperty(t,s,r.get?r:{enumerable:!0,get:function(){return e[s]}})}})),t.default=e,Object.freeze(t)}var c=a(e),u=o(t),l=o(s),d=a(r),h=o(i);function f(e,t){t&&t.forEach(e.add,e)}class p{constructor(e){this.undetermined=new Set,this.attrNames=new Set,this.attrValues=new Set,this.classes=new Set,this.ids=new Set,this.tags=new Set,this.merge(e)}merge(e){return Array.isArray(e)?f(this.undetermined,e):e instanceof p?(f(this.undetermined,e.undetermined),f(this.attrNames,e.attrNames),f(this.attrValues,e.attrValues),f(this.classes,e.classes),f(this.ids,e.ids),f(this.tags,e.tags)):(f(this.undetermined,e.undetermined),e.attributes&&(f(this.attrNames,e.attributes.names),f(this.attrValues,e.attributes.values)),f(this.classes,e.classes),f(this.ids,e.ids),f(this.tags,e.tags)),this}hasAttrName(e){return this.attrNames.has(e)||this.undetermined.has(e)}someAttrValue(e){for(const t of this.attrValues)if(e(t))return!0;for(const t of this.undetermined)if(e(t))return!0;return!1}hasAttrPrefix(e){return this.someAttrValue((t=>t.startsWith(e)))}hasAttrSuffix(e){return this.someAttrValue((t=>t.endsWith(e)))}hasAttrSubstr(e){return e.trim().split(" ").every((e=>this.someAttrValue((t=>t.includes(e)))))}hasAttrValue(e){return this.attrValues.has(e)||this.undetermined.has(e)}hasClass(e){return this.classes.has(e)||this.undetermined.has(e)}hasId(e){return this.ids.has(e)||this.undetermined.has(e)}hasTag(e){return this.tags.has(e)||this.undetermined.has(e)}}const m=["*",":root",":after",":before"],g={css:[],content:[],defaultExtractor:e=>e.match(/[A-Za-z0-9_-]+/g)||[],extractors:[],fontFace:!1,keyframes:!1,rejected:!1,rejectedCss:!1,stdin:!1,stdout:!1,variables:!1,safelist:{standard:[],deep:[],greedy:[],variables:[],keyframes:[]},blocklist:[],skippedContentGlobs:[],dynamicAttributes:[]};function v(e,t){const s=[];return e.replace(t,(function(){const t=arguments,r=Array.prototype.slice.call(t,0,-2);return r.input=t[t.length-1],r.index=t[t.length-2],s.push(r),e})),s}class y{constructor(e){this.nodes=[],this.isUsed=!1,this.value=e}}class S{constructor(){this.nodes=new Map,this.usedVariables=new Set,this.safelist=[]}addVariable(e){const{prop:t}=e;if(this.nodes.has(t)){const s=new y(e),r=this.nodes.get(t)||[];this.nodes.set(t,[...r,s])}else{const s=new y(e);this.nodes.set(t,[s])}}addVariableUsage(e,t){const{prop:s}=e,r=this.nodes.get(s);for(const e of t){const t=e[1];if(this.nodes.has(t)){const e=this.nodes.get(t);null==r||r.forEach((t=>{null==e||e.forEach((e=>t.nodes.push(e)))}))}}}addVariableUsageInProperties(e){for(const t of e){const e=t[1];this.usedVariables.add(e)}}setAsUsed(e){const t=this.nodes.get(e);if(t){const e=[...t];for(;0!==e.length;){const t=e.pop();t&&!t.isUsed&&(t.isUsed=!0,e.push(...t.nodes))}}}removeUnused(){for(const e of this.usedVariables){const t=this.nodes.get(e);if(t)for(const e of t){v(e.value.value,/var\((.+?)[,)]/g).forEach((e=>{this.usedVariables.has(e[1])||this.usedVariables.add(e[1])}))}}for(const e of this.usedVariables)this.setAsUsed(e);for(const[e,t]of this.nodes)for(const s of t)s.isUsed||this.isVariablesSafelisted(e)||s.value.remove()}isVariablesSafelisted(e){return this.safelist.some((t=>"string"==typeof t?t===e:t.test(e)))}}const b={access:n.promisify(c.access),readFile:n.promisify(c.readFile)};function w(e=[]){return Array.isArray(e)?{...g.safelist,standard:e}:{...g.safelist,...e}}async function x(e="purgecss.config.js"){let t;try{const s=l.default.resolve(process.cwd(),e);t=await function(e){return Promise.resolve().then((function(){return a(require(e))}))}(s)}catch(e){throw new Error(`Error loading the config file ${e.message}`)}return{...g,...t,safelist:w(t.safelist)}}async function A(e,t){return new p(await t(e))}function F(e,t){switch(t){case"next":return e.text.includes("purgecss ignore");case"start":return e.text.includes("purgecss start ignore");case"end":return e.text.includes("purgecss end ignore")}}function V(...e){const t=new p([]);return e.forEach(t.merge,t),t}function k(e){return e.replace(/(^["'])|(["']$)/g,"")}function j(e,t){if(!t.hasAttrName(e.attribute))return!1;if(void 0===e.value)return!0;switch(e.operator){case"$=":return t.hasAttrSuffix(e.value);case"~=":case"*=":return t.hasAttrSubstr(e.value);case"=":return t.hasAttrValue(e.value);case"|=":case"^=":return t.hasAttrPrefix(e.value);default:return!0}}function C(e,t){return t.hasId(e.value)}function U(e,t){return t.hasTag(e.value)}function E(e){return"atrule"===(null==e?void 0:e.type)}function R(e){return"rule"===(null==e?void 0:e.type)}class P{constructor(){this.ignore=!1,this.atRules={fontFace:[],keyframes:[]},this.usedAnimations=new Set,this.usedFontFaces=new Set,this.selectorsRemoved=new Set,this.removedNodes=[],this.variablesStructure=new S,this.options=g}collectDeclarationsData(e){const{prop:t,value:s}=e;if(this.options.variables){const r=v(s,/var\((.+?)[,)]/g);t.startsWith("--")?(this.variablesStructure.addVariable(e),r.length>0&&this.variablesStructure.addVariableUsage(e,r)):r.length>0&&this.variablesStructure.addVariableUsageInProperties(r)}if(!this.options.keyframes||"animation"!==t&&"animation-name"!==t)if(this.options.fontFace){if("font-family"===t)for(const e of s.split(",")){const t=k(e.trim());this.usedFontFaces.add(t)}}else;else for(const e of s.split(/[\s,]+/))this.usedAnimations.add(e)}getFileExtractor(e,t){const s=t.find((t=>t.extensions.find((t=>e.endsWith(t)))));return void 0===s?this.options.defaultExtractor:s.extractor}async extractSelectorsFromFiles(e,t){const s=new p([]);for(const r of e){let e=[];try{await b.access(r,c.constants.F_OK),e.push(r)}catch(t){e=u.default.sync(r,{nodir:!0,ignore:this.options.skippedContentGlobs})}for(const r of e){const e=await b.readFile(r,"utf-8"),i=this.getFileExtractor(r,t),n=await A(e,i);s.merge(n)}}return s}async extractSelectorsFromString(e,t){const s=new p([]);for(const{raw:r,extension:i}of e){const e=this.getFileExtractor(`.${i}`,t),n=await A(r,e);s.merge(n)}return s}evaluateAtRule(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name&&e.nodes)for(const t of e.nodes)"decl"===t.type&&"font-family"===t.prop&&this.atRules.fontFace.push({name:k(t.value),node:e})}evaluateRule(e,t){if(this.ignore)return;const s=e.prev();if(function(e){return"comment"===(null==e?void 0:e.type)}(s)&&F(s,"next"))return void s.remove();if(e.parent&&E(e.parent)&&e.parent.name.endsWith("keyframes"))return;if(!R(e))return;if(function(e){let t=!1;return e.walkComments((e=>{e&&"comment"===e.type&&e.text.includes("purgecss ignore current")&&(t=!0,e.remove())})),t}(e))return;let r=!0;const i=[];if(e.selector=h.default((e=>{e.walk((e=>{"selector"===e.type&&(r=this.shouldKeepSelector(e,t),r||(this.options.rejected&&this.selectorsRemoved.add(e.toString()),this.options.rejectedCss&&i.push(e.toString()),e.remove()))}))})).processSync(e.selector),r&&void 0!==e.nodes)for(const t of e.nodes)"decl"===t.type&&this.collectDeclarationsData(t);const n=e.parent;if(e.selector||e.remove(),function(e){return!!(R(e)&&!e.selector||(null==e?void 0:e.nodes)&&!e.nodes.length||E(e)&&(!e.nodes&&!e.params||!e.params&&e.nodes&&!e.nodes.length))}(n)&&(null==n||n.remove()),this.options.rejectedCss&&i.length>0){const t=e.clone(),s=null==n?void 0:n.clone().removeAll().append(t);t.selectors=i;const r=s||t;this.removedNodes.push(r)}}async getPurgedCSS(e,t){const s=[],r=[];for(const t of e)"string"==typeof t?r.push(...u.default.sync(t,{nodir:!0,ignore:this.options.skippedContentGlobs})):r.push(t);for(const e of r){const r="string"==typeof e?this.options.stdin?e:await b.readFile(e,"utf-8"):e.raw,i=d.parse(r);this.walkThroughCSS(i,t),this.options.fontFace&&this.removeUnusedFontFaces(),this.options.keyframes&&this.removeUnusedKeyframes(),this.options.variables&&this.removeUnusedCSSVariables();const n={css:i.toString(),file:"string"==typeof e?e:e.name};this.options.rejected&&(n.rejected=Array.from(this.selectorsRemoved),this.selectorsRemoved.clear()),this.options.rejectedCss&&(n.rejectedCss=d.root({nodes:this.removedNodes}).toString()),s.push(n)}return s}isKeyframesSafelisted(e){return this.options.safelist.keyframes.some((t=>"string"==typeof t?t===e:t.test(e)))}isSelectorBlocklisted(e){return this.options.blocklist.some((t=>"string"==typeof t?t===e:t.test(e)))}isSelectorSafelisted(e){const t=this.options.safelist.standard.some((t=>"string"==typeof t?t===e:t.test(e))),s=/^::.*/.test(e);return m.includes(e)||s||t}isSelectorSafelistedDeep(e){return this.options.safelist.deep.some((t=>t.test(e)))}isSelectorSafelistedGreedy(e){return this.options.safelist.greedy.some((t=>t.test(e)))}async purge(e){this.options="object"!=typeof e?await x(e):{...g,...e,safelist:w(e.safelist)};const{content:t,css:s,extractors:r,safelist:i}=this.options;this.options.variables&&(this.variablesStructure.safelist=i.variables||[]);const n=t.filter((e=>"string"==typeof e)),o=t.filter((e=>"object"==typeof e)),a=await this.extractSelectorsFromFiles(n,r),c=await this.extractSelectorsFromString(o,r);return this.getPurgedCSS(s,V(a,c))}removeUnusedCSSVariables(){this.variablesStructure.removeUnused()}removeUnusedFontFaces(){for(const{name:e,node:t}of this.atRules.fontFace)this.usedFontFaces.has(e)||t.remove()}removeUnusedKeyframes(){for(const e of this.atRules.keyframes)this.usedAnimations.has(e.params)||this.isKeyframesSafelisted(e.params)||e.remove()}getSelectorValue(e){return"attribute"===e.type&&e.attribute||e.value}shouldKeepSelector(e,t){if(function(e){return e.parent&&"pseudo"===e.parent.type&&e.parent.value.startsWith(":")||!1}(e))return!0;if(this.options.safelist.greedy.length>0){if(e.nodes.map(this.getSelectorValue).some((e=>e&&this.isSelectorSafelistedGreedy(e))))return!0}let s=!1;for(const i of e.nodes){const e=this.getSelectorValue(i);if(e&&this.isSelectorSafelistedDeep(e))return!0;if(e&&(m.includes(e)||this.isSelectorSafelisted(e)))s=!0;else{if(e&&this.isSelectorBlocklisted(e))return!1;switch(i.type){case"attribute":s=!![...this.options.dynamicAttributes,"value","checked","selected","open"].includes(i.attribute)||j(i,t);break;case"class":r=i,s=t.hasClass(r.value);break;case"id":s=C(i,t);break;case"tag":s=U(i,t);break;default:continue}if(!s)return!1}}var r;return s}walkThroughCSS(e,t){e.walk((e=>"rule"===e.type?this.evaluateRule(e,t):"atrule"===e.type?this.evaluateAtRule(e):void("comment"===e.type&&(F(e,"start")?(this.ignore=!0,e.remove()):F(e,"end")&&(this.ignore=!1,e.remove())))))}}exports.PurgeCSS=P,exports.default=P,exports.defaultOptions=g,exports.mergeExtractorSelectors=V,exports.setOptions=x,exports.standardizeSafelist=w;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("fs"),t=require("glob"),s=require("path"),r=require("postcss"),i=require("postcss-selector-parser"),o=require("util");function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function a(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(s){if("default"!==s){var r=Object.getOwnPropertyDescriptor(e,s);Object.defineProperty(t,s,r.get?r:{enumerable:!0,get:function(){return e[s]}})}})),t.default=e,Object.freeze(t)}var c=a(e),u=a(t),l=a(s),d=a(r),h=n(i);function f(e,t){t&&t.forEach(e.add,e)}class ExtractorResultSets{constructor(e){this.undetermined=new Set,this.attrNames=new Set,this.attrValues=new Set,this.classes=new Set,this.ids=new Set,this.tags=new Set,this.merge(e)}merge(e){return Array.isArray(e)?f(this.undetermined,e):e instanceof ExtractorResultSets?(f(this.undetermined,e.undetermined),f(this.attrNames,e.attrNames),f(this.attrValues,e.attrValues),f(this.classes,e.classes),f(this.ids,e.ids),f(this.tags,e.tags)):(f(this.undetermined,e.undetermined),e.attributes&&(f(this.attrNames,e.attributes.names),f(this.attrValues,e.attributes.values)),f(this.classes,e.classes),f(this.ids,e.ids),f(this.tags,e.tags)),this}hasAttrName(e){return this.attrNames.has(e)||this.undetermined.has(e)}someAttrValue(e){for(const t of this.attrValues)if(e(t))return!0;for(const t of this.undetermined)if(e(t))return!0;return!1}hasAttrPrefix(e){return this.someAttrValue((t=>t.startsWith(e)))}hasAttrSuffix(e){return this.someAttrValue((t=>t.endsWith(e)))}hasAttrSubstr(e){return e.trim().split(" ").every((e=>this.someAttrValue((t=>t.includes(e)))))}hasAttrValue(e){return this.attrValues.has(e)||this.undetermined.has(e)}hasClass(e){return this.classes.has(e)||this.undetermined.has(e)}hasId(e){return this.ids.has(e)||this.undetermined.has(e)}hasTag(e){return this.tags.has(e)||this.undetermined.has(e)}}const p=["*",":root",":after",":before"],m={css:[],content:[],defaultExtractor:e=>e.match(/[A-Za-z0-9_-]+/g)||[],extractors:[],fontFace:!1,keyframes:!1,rejected:!1,rejectedCss:!1,sourceMap:!1,stdin:!1,stdout:!1,variables:!1,safelist:{standard:[],deep:[],greedy:[],variables:[],keyframes:[]},blocklist:[],skippedContentGlobs:[],dynamicAttributes:[]};function g(e,t){const s=[];return e.replace(t,(function(){const t=arguments,r=Array.prototype.slice.call(t,0,-2);return r.input=t[t.length-1],r.index=t[t.length-2],s.push(r),e})),s}class VariableNode{constructor(e){this.nodes=[],this.isUsed=!1,this.value=e}}class VariablesStructure{constructor(){this.nodes=new Map,this.usedVariables=new Set,this.safelist=[]}addVariable(e){const{prop:t}=e;if(this.nodes.has(t)){const s=new VariableNode(e),r=this.nodes.get(t)||[];this.nodes.set(t,[...r,s])}else{const s=new VariableNode(e);this.nodes.set(t,[s])}}addVariableUsage(e,t){const{prop:s}=e,r=this.nodes.get(s);for(const e of t){const t=e[1];if(this.nodes.has(t)){const e=this.nodes.get(t);null==r||r.forEach((t=>{null==e||e.forEach((e=>t.nodes.push(e)))}))}}}addVariableUsageInProperties(e){for(const t of e){const e=t[1];this.usedVariables.add(e)}}setAsUsed(e){const t=this.nodes.get(e);if(t){const e=[...t];for(;0!==e.length;){const t=e.pop();t&&!t.isUsed&&(t.isUsed=!0,e.push(...t.nodes))}}}removeUnused(){for(const e of this.usedVariables){const t=this.nodes.get(e);if(t)for(const e of t){g(e.value.value,/var\((.+?)[,)]/g).forEach((e=>{this.usedVariables.has(e[1])||this.usedVariables.add(e[1])}))}}for(const e of this.usedVariables)this.setAsUsed(e);for(const[e,t]of this.nodes)for(const s of t)s.isUsed||this.isVariablesSafelisted(e)||s.value.remove()}isVariablesSafelisted(e){return this.safelist.some((t=>"string"==typeof t?t===e:t.test(e)))}}const v={access:o.promisify(c.access),readFile:o.promisify(c.readFile)};function S(e=[]){return Array.isArray(e)?{...m.safelist,standard:e}:{...m.safelist,...e}}async function y(e="purgecss.config.js"){let t;try{const s=l.resolve(process.cwd(),e);t=await function(e){return Promise.resolve().then((function(){return a(require(e))}))}(s)}catch(e){if(e instanceof Error)throw new Error(`Error loading the config file ${e.message}`);throw new Error}return{...m,...t,safelist:S(t.safelist)}}async function b(e,t){return new ExtractorResultSets(await t(e))}function w(e,t){switch(t){case"next":return e.text.includes("purgecss ignore");case"start":return e.text.includes("purgecss start ignore");case"end":return e.text.includes("purgecss end ignore")}}function x(...e){const t=new ExtractorResultSets([]);return e.forEach(t.merge,t),t}function V(e){return e.replace(/(^["'])|(["']$)/g,"")}function A(e,t){if(!t.hasAttrName(e.attribute))return!1;if(void 0===e.value)return!0;switch(e.operator){case"$=":return t.hasAttrSuffix(e.value);case"~=":case"*=":return t.hasAttrSubstr(e.value);case"=":return t.hasAttrValue(e.value);case"|=":case"^=":return t.hasAttrPrefix(e.value);default:return!0}}function F(e,t){return t.hasId(e.value)}function k(e,t){return t.hasTag(e.value)}function E(e){return"atrule"===(null==e?void 0:e.type)}function R(e){return"rule"===(null==e?void 0:e.type)}exports.ExtractorResultSets=ExtractorResultSets,exports.PurgeCSS=class PurgeCSS{constructor(){this.ignore=!1,this.atRules={fontFace:[],keyframes:[]},this.usedAnimations=new Set,this.usedFontFaces=new Set,this.selectorsRemoved=new Set,this.removedNodes=[],this.variablesStructure=new VariablesStructure,this.options=m}collectDeclarationsData(e){const{prop:t,value:s}=e;if(this.options.variables){const r=g(s,/var\((.+?)[,)]/g);t.startsWith("--")?(this.variablesStructure.addVariable(e),r.length>0&&this.variablesStructure.addVariableUsage(e,r)):r.length>0&&this.variablesStructure.addVariableUsageInProperties(r)}if(!this.options.keyframes||"animation"!==t&&"animation-name"!==t)if(this.options.fontFace){if("font-family"===t)for(const e of s.split(",")){const t=V(e.trim());this.usedFontFaces.add(t)}}else;else for(const e of s.split(/[\s,]+/))this.usedAnimations.add(e)}getFileExtractor(e,t){const s=t.find((t=>t.extensions.find((t=>e.endsWith(t)))));return void 0===s?this.options.defaultExtractor:s.extractor}async extractSelectorsFromFiles(e,t){const s=new ExtractorResultSets([]);for(const r of e){let e=[];try{await v.access(r,c.constants.F_OK),e.push(r)}catch(t){e=u.sync(r,{nodir:!0,ignore:this.options.skippedContentGlobs})}for(const r of e){const e=await v.readFile(r,"utf-8"),i=this.getFileExtractor(r,t),o=await b(e,i);s.merge(o)}}return s}async extractSelectorsFromString(e,t){const s=new ExtractorResultSets([]);for(const{raw:r,extension:i}of e){const e=this.getFileExtractor(`.${i}`,t),o=await b(r,e);s.merge(o)}return s}evaluateAtRule(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name&&e.nodes)for(const t of e.nodes)"decl"===t.type&&"font-family"===t.prop&&this.atRules.fontFace.push({name:V(t.value),node:e})}evaluateRule(e,t){if(this.ignore)return;const s=e.prev();if(function(e){return"comment"===(null==e?void 0:e.type)}(s)&&w(s,"next"))return void s.remove();if(e.parent&&E(e.parent)&&e.parent.name.endsWith("keyframes"))return;if(!R(e))return;if(function(e){let t=!1;return e.walkComments((e=>{e&&"comment"===e.type&&e.text.includes("purgecss ignore current")&&(t=!0,e.remove())})),t}(e))return;let r=!0;const i=[];if(e.selector=h.default((e=>{e.walk((e=>{"selector"===e.type&&(r=this.shouldKeepSelector(e,t),r||(this.options.rejected&&this.selectorsRemoved.add(e.toString()),this.options.rejectedCss&&i.push(e.toString()),e.remove()))}))})).processSync(e.selector),r&&void 0!==e.nodes)for(const t of e.nodes)"decl"===t.type&&this.collectDeclarationsData(t);const o=e.parent;if(e.selector||e.remove(),function(e){return!!(R(e)&&!e.selector||(null==e?void 0:e.nodes)&&!e.nodes.length||E(e)&&(!e.nodes&&!e.params||!e.params&&e.nodes&&!e.nodes.length))}(o)&&(null==o||o.remove()),this.options.rejectedCss&&i.length>0){const t=e.clone(),s=null==o?void 0:o.clone().removeAll().append(t);t.selectors=i;const r=s||t;this.removedNodes.push(r)}}async getPurgedCSS(e,t){var s;const r=[],i=[];for(const t of e)"string"==typeof t?i.push(...u.sync(t,{nodir:!0,ignore:this.options.skippedContentGlobs})):i.push(t);for(const e of i){const i="string"==typeof e?this.options.stdin?e:await v.readFile(e,"utf-8"):e.raw,o="string"==typeof e&&!this.options.stdin,n=d.parse(i,{from:o?e:void 0});this.walkThroughCSS(n,t),this.options.fontFace&&this.removeUnusedFontFaces(),this.options.keyframes&&this.removeUnusedKeyframes(),this.options.variables&&this.removeUnusedCSSVariables();const a=n.toResult({map:this.options.sourceMap,to:"object"==typeof this.options.sourceMap?this.options.sourceMap.to:void 0}),c={css:a.toString(),file:"string"==typeof e?e:e.name};this.options.sourceMap&&(c.sourceMap=null===(s=a.map)||void 0===s?void 0:s.toString()),this.options.rejected&&(c.rejected=Array.from(this.selectorsRemoved),this.selectorsRemoved.clear()),this.options.rejectedCss&&(c.rejectedCss=d.root({nodes:this.removedNodes}).toString()),r.push(c)}return r}isKeyframesSafelisted(e){return this.options.safelist.keyframes.some((t=>"string"==typeof t?t===e:t.test(e)))}isSelectorBlocklisted(e){return this.options.blocklist.some((t=>"string"==typeof t?t===e:t.test(e)))}isSelectorSafelisted(e){const t=this.options.safelist.standard.some((t=>"string"==typeof t?t===e:t.test(e))),s=/^::.*/.test(e);return p.includes(e)||s||t}isSelectorSafelistedDeep(e){return this.options.safelist.deep.some((t=>t.test(e)))}isSelectorSafelistedGreedy(e){return this.options.safelist.greedy.some((t=>t.test(e)))}async purge(e){this.options="object"!=typeof e?await y(e):{...m,...e,safelist:S(e.safelist)};const{content:t,css:s,extractors:r,safelist:i}=this.options;this.options.variables&&(this.variablesStructure.safelist=i.variables||[]);const o=t.filter((e=>"string"==typeof e)),n=t.filter((e=>"object"==typeof e)),a=await this.extractSelectorsFromFiles(o,r),c=await this.extractSelectorsFromString(n,r);return this.getPurgedCSS(s,x(a,c))}removeUnusedCSSVariables(){this.variablesStructure.removeUnused()}removeUnusedFontFaces(){for(const{name:e,node:t}of this.atRules.fontFace)this.usedFontFaces.has(e)||t.remove()}removeUnusedKeyframes(){for(const e of this.atRules.keyframes)this.usedAnimations.has(e.params)||this.isKeyframesSafelisted(e.params)||e.remove()}getSelectorValue(e){return"attribute"===e.type&&e.attribute||e.value}shouldKeepSelector(e,t){if(function(e){return e.parent&&"pseudo"===e.parent.type&&e.parent.value.startsWith(":")||!1}(e))return!0;if(this.options.safelist.greedy.length>0){if(e.nodes.map(this.getSelectorValue).some((e=>e&&this.isSelectorSafelistedGreedy(e))))return!0}let s=!1;for(const i of e.nodes){const e=this.getSelectorValue(i);if(e&&this.isSelectorSafelistedDeep(e))return!0;if(e&&(p.includes(e)||this.isSelectorSafelisted(e)))s=!0;else{if(e&&this.isSelectorBlocklisted(e))return!1;switch(i.type){case"attribute":s=!![...this.options.dynamicAttributes,"value","checked","selected","open"].includes(i.attribute)||A(i,t);break;case"class":r=i,s=t.hasClass(r.value);break;case"id":s=F(i,t);break;case"tag":s=k(i,t);break;default:continue}if(!s)return!1}}var r;return s}walkThroughCSS(e,t){e.walk((e=>"rule"===e.type?this.evaluateRule(e,t):"atrule"===e.type?this.evaluateAtRule(e):void("comment"===e.type&&(w(e,"start")?(this.ignore=!0,e.remove()):w(e,"end")&&(this.ignore=!1,e.remove())))))}},exports.defaultOptions=m,exports.mergeExtractorSelectors=x,exports.setOptions=y,exports.standardizeSafelist=S;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "purgecss",
3
- "version": "4.1.3",
3
+ "version": "5.0.0",
4
4
  "description": "Remove unused css selectors",
5
5
  "author": "Ffloriel",
6
6
  "homepage": "https://purgecss.com",
@@ -36,16 +36,17 @@
36
36
  "url": "git+https://github.com/FullHuman/purgecss.git"
37
37
  },
38
38
  "scripts": {
39
- "test": "echo \"Error: run tests from root\" && exit 1"
39
+ "build": "ts-node build.ts",
40
+ "test": "jest"
40
41
  },
41
42
  "dependencies": {
42
- "commander": "^8.0.0",
43
- "glob": "^7.1.7",
44
- "postcss": "^8.3.5",
45
- "postcss-selector-parser": "^6.0.6"
43
+ "commander": "^9.0.0",
44
+ "glob": "^8.0.3",
45
+ "postcss": "^8.4.4",
46
+ "postcss-selector-parser": "^6.0.7"
46
47
  },
47
48
  "devDependencies": {
48
- "@types/glob": "^7.1.1"
49
+ "@types/glob": "^7.2.0"
49
50
  },
50
51
  "bugs": {
51
52
  "url": "https://github.com/FullHuman/purgecss/issues"
@@ -53,6 +54,5 @@
53
54
  "publishConfig": {
54
55
  "access": "public",
55
56
  "registry": "https://registry.npmjs.org/"
56
- },
57
- "gitHead": "37e5053a446880d12fd2f55abfc362c3dac9c49c"
57
+ }
58
58
  }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2020 Full Human
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
package/bin/purgecss.d.ts DELETED
@@ -1 +0,0 @@
1
- export {};
@@ -1,334 +0,0 @@
1
- import * as postcss from "postcss";
2
- type PostCSSRoot = postcss.Root;
3
- interface AtRules {
4
- fontFace: Array<{
5
- name: string;
6
- node: postcss.AtRule;
7
- }>;
8
- keyframes: postcss.AtRule[];
9
- }
10
- interface RawContent<T = string> {
11
- extension: string;
12
- raw: T;
13
- }
14
- interface RawCSS {
15
- raw: string;
16
- name?: string;
17
- }
18
- interface ExtractorResultDetailed {
19
- attributes: {
20
- names: string[];
21
- values: string[];
22
- };
23
- classes: string[];
24
- ids: string[];
25
- tags: string[];
26
- undetermined: string[];
27
- }
28
- type ExtractorResult = ExtractorResultDetailed | string[];
29
- type ExtractorFunction<T = string> = (content: T) => ExtractorResult;
30
- interface Extractors {
31
- extensions: string[];
32
- extractor: ExtractorFunction;
33
- }
34
- type IgnoreType = "end" | "start" | "next";
35
- type StringRegExpArray = Array<RegExp | string>;
36
- type ComplexSafelist = {
37
- standard?: StringRegExpArray;
38
- deep?: RegExp[];
39
- greedy?: RegExp[];
40
- variables?: StringRegExpArray;
41
- keyframes?: StringRegExpArray;
42
- };
43
- type UserDefinedSafelist = StringRegExpArray | ComplexSafelist;
44
- interface UserDefinedOptions {
45
- content: Array<string | RawContent>;
46
- css: Array<string | RawCSS>;
47
- defaultExtractor?: ExtractorFunction;
48
- extractors?: Array<Extractors>;
49
- fontFace?: boolean;
50
- keyframes?: boolean;
51
- output?: string;
52
- rejected?: boolean;
53
- rejectedCss?: boolean;
54
- stdin?: boolean;
55
- stdout?: boolean;
56
- variables?: boolean;
57
- safelist?: UserDefinedSafelist;
58
- blocklist?: StringRegExpArray;
59
- skippedContentGlobs?: Array<string>;
60
- dynamicAttributes?: string[];
61
- }
62
- interface Options {
63
- content: Array<string | RawContent>;
64
- css: Array<string | RawCSS>;
65
- defaultExtractor: ExtractorFunction;
66
- extractors: Array<Extractors>;
67
- fontFace: boolean;
68
- keyframes: boolean;
69
- output?: string;
70
- rejected: boolean;
71
- rejectedCss: boolean;
72
- stdin: boolean;
73
- stdout: boolean;
74
- variables: boolean;
75
- safelist: Required<ComplexSafelist>;
76
- blocklist: StringRegExpArray;
77
- skippedContentGlobs: Array<string>;
78
- dynamicAttributes: string[];
79
- }
80
- interface ResultPurge {
81
- css: string;
82
- rejectedCss?: string;
83
- file?: string;
84
- rejected?: string[];
85
- }
86
- declare class ExtractorResultSets {
87
- private undetermined;
88
- private attrNames;
89
- private attrValues;
90
- private classes;
91
- private ids;
92
- private tags;
93
- constructor(er: ExtractorResult);
94
- merge(that: ExtractorResult | ExtractorResultSets): this;
95
- hasAttrName(name: string): boolean;
96
- private someAttrValue;
97
- hasAttrPrefix(prefix: string): boolean;
98
- hasAttrSuffix(suffix: string): boolean;
99
- hasAttrSubstr(substr: string): boolean;
100
- hasAttrValue(value: string): boolean;
101
- hasClass(name: string): boolean;
102
- hasId(id: string): boolean;
103
- hasTag(tag: string): boolean;
104
- }
105
- declare const defaultOptions: Options;
106
- declare function standardizeSafelist(
107
- userDefinedSafelist?: UserDefinedSafelist
108
- ): Required<ComplexSafelist>;
109
- /**
110
- * Load the configuration file from the path
111
- * @param configFile Path of the config file
112
- */
113
- declare function setOptions(configFile?: string): Promise<Options>;
114
- /**
115
- * Merge two extractor selectors
116
- * @param extractorSelectorsA extractor selectors A
117
- * @param extractorSelectorsB extractor selectors B
118
- */
119
- declare function mergeExtractorSelectors(
120
- ...extractors: (ExtractorResultDetailed | ExtractorResultSets)[]
121
- ): ExtractorResultSets;
122
- declare class PurgeCSS {
123
- private ignore;
124
- private atRules;
125
- private usedAnimations;
126
- private usedFontFaces;
127
- selectorsRemoved: Set<string>;
128
- removedNodes: postcss.Node[];
129
- private variablesStructure;
130
- options: Options;
131
- private collectDeclarationsData;
132
- /**
133
- * Get the extractor corresponding to the extension file
134
- * @param filename Name of the file
135
- * @param extractors Array of extractors definition
136
- */
137
- /**
138
- * Get the extractor corresponding to the extension file
139
- * @param filename Name of the file
140
- * @param extractors Array of extractors definition
141
- */
142
- private getFileExtractor;
143
- /**
144
- * Extract the selectors present in the files using a purgecss extractor
145
- * @param files Array of files path or glob pattern
146
- * @param extractors Array of extractors
147
- */
148
- /**
149
- * Extract the selectors present in the files using a purgecss extractor
150
- * @param files Array of files path or glob pattern
151
- * @param extractors Array of extractors
152
- */
153
- extractSelectorsFromFiles(
154
- files: string[],
155
- extractors: Extractors[]
156
- ): Promise<ExtractorResultSets>;
157
- /**
158
- * Extract the selectors present in the passed string using a PurgeCSS extractor
159
- * @param content Array of content
160
- * @param extractors Array of extractors
161
- */
162
- /**
163
- * Extract the selectors present in the passed string using a PurgeCSS extractor
164
- * @param content Array of content
165
- * @param extractors Array of extractors
166
- */
167
- extractSelectorsFromString(
168
- content: RawContent[],
169
- extractors: Extractors[]
170
- ): Promise<ExtractorResultSets>;
171
- /**
172
- * Evaluate at-rule and register it for future reference
173
- * @param node node of postcss AST
174
- */
175
- /**
176
- * Evaluate at-rule and register it for future reference
177
- * @param node node of postcss AST
178
- */
179
- private evaluateAtRule;
180
- /**
181
- * Evaluate css selector and decide if it should be removed or not
182
- * @param node node of postcss AST
183
- * @param selectors selectors used in content files
184
- */
185
- /**
186
- * Evaluate css selector and decide if it should be removed or not
187
- * @param node node of postcss AST
188
- * @param selectors selectors used in content files
189
- */
190
- private evaluateRule;
191
- /**
192
- * Get the purged version of the css based on the files
193
- * @param cssOptions css options, files or raw strings
194
- * @param selectors set of extracted css selectors
195
- */
196
- /**
197
- * Get the purged version of the css based on the files
198
- * @param cssOptions css options, files or raw strings
199
- * @param selectors set of extracted css selectors
200
- */
201
- getPurgedCSS(
202
- cssOptions: Array<string | RawCSS>,
203
- selectors: ExtractorResultSets
204
- ): Promise<ResultPurge[]>;
205
- /**
206
- * Check if the keyframe is safelisted with the option safelist keyframes
207
- * @param keyframesName name of the keyframe animation
208
- */
209
- /**
210
- * Check if the keyframe is safelisted with the option safelist keyframes
211
- * @param keyframesName name of the keyframe animation
212
- */
213
- private isKeyframesSafelisted;
214
- /**
215
- * Check if the selector is blocklisted with the option blocklist
216
- * @param selector css selector
217
- */
218
- /**
219
- * Check if the selector is blocklisted with the option blocklist
220
- * @param selector css selector
221
- */
222
- private isSelectorBlocklisted;
223
- /**
224
- * Check if the selector is safelisted with the option safelist standard
225
- * @param selector css selector
226
- */
227
- /**
228
- * Check if the selector is safelisted with the option safelist standard
229
- * @param selector css selector
230
- */
231
- private isSelectorSafelisted;
232
- /**
233
- * Check if the selector is safelisted with the option safelist deep
234
- * @param selector selector
235
- */
236
- /**
237
- * Check if the selector is safelisted with the option safelist deep
238
- * @param selector selector
239
- */
240
- private isSelectorSafelistedDeep;
241
- /**
242
- * Check if the selector is safelisted with the option safelist greedy
243
- * @param selector selector
244
- */
245
- /**
246
- * Check if the selector is safelisted with the option safelist greedy
247
- * @param selector selector
248
- */
249
- private isSelectorSafelistedGreedy;
250
- /**
251
- * Remove unused css
252
- * @param userOptions PurgeCSS options
253
- */
254
- /**
255
- * Remove unused css
256
- * @param userOptions PurgeCSS options
257
- */
258
- purge(
259
- userOptions: UserDefinedOptions | string | undefined
260
- ): Promise<ResultPurge[]>;
261
- /**
262
- * Remove unused CSS variables
263
- */
264
- /**
265
- * Remove unused CSS variables
266
- */
267
- removeUnusedCSSVariables(): void;
268
- /**
269
- * Remove unused font-faces
270
- */
271
- /**
272
- * Remove unused font-faces
273
- */
274
- removeUnusedFontFaces(): void;
275
- /**
276
- * Remove unused keyframes
277
- */
278
- /**
279
- * Remove unused keyframes
280
- */
281
- removeUnusedKeyframes(): void;
282
- /**
283
- * Transform a selector node into a string
284
- */
285
- /**
286
- * Transform a selector node into a string
287
- */
288
- private getSelectorValue;
289
- /**
290
- * Determine if the selector should be kept, based on the selectors found in the files
291
- * @param selector set of css selectors found in the content files or string
292
- * @param selectorsFromExtractor selectors in the css rule
293
- */
294
- /**
295
- * Determine if the selector should be kept, based on the selectors found in the files
296
- * @param selector set of css selectors found in the content files or string
297
- * @param selectorsFromExtractor selectors in the css rule
298
- */
299
- private shouldKeepSelector;
300
- /**
301
- * Walk through the CSS AST and remove unused CSS
302
- * @param root root node of the postcss AST
303
- * @param selectors selectors used in content files
304
- */
305
- /**
306
- * Walk through the CSS AST and remove unused CSS
307
- * @param root root node of the postcss AST
308
- * @param selectors selectors used in content files
309
- */
310
- walkThroughCSS(root: PostCSSRoot, selectors: ExtractorResultSets): void;
311
- }
312
- export {
313
- PurgeCSS as default,
314
- PurgeCSS,
315
- defaultOptions,
316
- PostCSSRoot,
317
- AtRules,
318
- RawContent,
319
- RawCSS,
320
- ExtractorResultDetailed,
321
- ExtractorResult,
322
- ExtractorFunction,
323
- Extractors,
324
- IgnoreType,
325
- StringRegExpArray,
326
- ComplexSafelist,
327
- UserDefinedSafelist,
328
- UserDefinedOptions,
329
- Options,
330
- ResultPurge,
331
- standardizeSafelist,
332
- setOptions,
333
- mergeExtractorSelectors,
334
- };