purgecss 4.1.2 → 4.1.3

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.
package/bin/purgecss.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- "use strict";var e=require("commander"),t=require("fs"),s=require("glob"),r=require("path"),o=require("postcss"),i=require("postcss-selector-parser"),n=require("util");function a(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function c(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 l=c(t),u=a(t),d=a(s),f=a(r),h=c(o),p=a(i),m="4.1.1",g="Remove unused css selectors";function v(e,t){t&&t.forEach(e.add,e)}class y{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)?v(this.undetermined,e):e instanceof y?(v(this.undetermined,e.undetermined),v(this.attrNames,e.attrNames),v(this.attrValues,e.attrValues),v(this.classes,e.classes),v(this.ids,e.ids),v(this.tags,e.tags)):(v(this.undetermined,e.undetermined),e.attributes&&(v(this.attrNames,e.attributes.names),v(this.attrValues,e.attributes.values)),v(this.classes,e.classes),v(this.ids,e.ids),v(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 b=["*",":root",":after",":before"],S={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 w(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 k{constructor(e){this.nodes=[],this.isUsed=!1,this.value=e}}class F{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 k(e),r=this.nodes.get(t)||[];this.nodes.set(t,[...r,s])}else{const s=new k(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){w(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 A={access:n.promisify(l.access),readFile:n.promisify(l.readFile)};function V(e=[]){return Array.isArray(e)?{...S.safelist,standard:e}:{...S.safelist,...e}}async function j(e="purgecss.config.js"){let t;try{const s=f.default.resolve(process.cwd(),e);t=await function(e){return Promise.resolve().then((function(){return c(require(e))}))}(s)}catch(e){throw new Error(`Error loading the config file ${e.message}`)}return{...S,...t,safelist:V(t.safelist)}}async function x(e,t){return new y(await t(e))}function C(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 U(e){return e.replace(/(^["'])|(["']$)/g,"")}function R(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 E(e,t){return t.hasId(e.value)}function N(e,t){return t.hasTag(e.value)}function P(e){return"atrule"===(null==e?void 0:e.type)}function q(e){return"rule"===(null==e?void 0:e.type)}class G{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 F,this.options=S}collectDeclarationsData(e){const{prop:t,value:s}=e;if(this.options.variables){const r=w(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=U(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 y([]);for(const r of e){let e=[];try{await A.access(r,l.constants.F_OK),e.push(r)}catch(t){e=d.default.sync(r,{nodir:!0,ignore:this.options.skippedContentGlobs})}for(const r of e){const e=await A.readFile(r,"utf-8"),o=this.getFileExtractor(r,t),i=await x(e,o);s.merge(i)}}return s}async extractSelectorsFromString(e,t){const s=new y([]);for(const{raw:r,extension:o}of e){const e=this.getFileExtractor(`.${o}`,t),i=await x(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:U(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)&&C(s,"next"))return void s.remove();if(e.parent&&P(e.parent)&&e.parent.name.endsWith("keyframes"))return;if(!q(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=p.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&&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 i=e.parent;if(e.selector||e.remove(),function(e){return!!(q(e)&&!e.selector||(null==e?void 0:e.nodes)&&!e.nodes.length||P(e)&&(!e.nodes&&!e.params||!e.params&&e.nodes&&!e.nodes.length))}(i)&&(null==i||i.remove()),this.options.rejectedCss&&o.length>0){const t=e.clone(),s=null==i?void 0:i.clone().removeAll().append(t);t.selectors=o;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(...d.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 A.readFile(e,"utf-8"):e.raw,o=h.parse(r);this.walkThroughCSS(o,t),this.options.fontFace&&this.removeUnusedFontFaces(),this.options.keyframes&&this.removeUnusedKeyframes(),this.options.variables&&this.removeUnusedCSSVariables();const i={css:o.toString(),file:"string"==typeof e?e:e.name};this.options.rejected&&(i.rejected=Array.from(this.selectorsRemoved),this.selectorsRemoved.clear()),this.options.rejectedCss&&(i.rejectedCss=h.root({nodes:this.removedNodes}).toString()),s.push(i)}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 b.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 j(e):{...S,...e,safelist:V(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)),n=t.filter((e=>"object"==typeof e)),a=await this.extractSelectorsFromFiles(i,r),c=await this.extractSelectorsFromString(n,r);return this.getPurgedCSS(s,function(...e){const t=new y([]);return e.forEach(t.merge,t),t}(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 o of e.nodes){const e=this.getSelectorValue(o);if(e&&this.isSelectorSafelistedDeep(e))return!0;if(e&&(b.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)||R(o,t);break;case"class":r=o,s=t.hasClass(r.value);break;case"id":s=E(o,t);break;case"tag":s=N(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&&(C(e,"start")?(this.ignore=!0,e.remove()):C(e,"end")&&(this.ignore=!1,e.remove())))))}}async function O(e,t){try{await u.default.promises.writeFile(e,t)}catch(e){console.error(e.message)}}try{!async function(){var t;e.program.description(g).version(m).usage("--css <css...> --content <content...> [options]"),e.program.option("-con, --content <files...>","glob of content files").option("-css, --css <files...>","glob of css files").option("-c, --config <path>","path to the configuration file").option("-o, --output <path>","file path directory to write purged css files to").option("-font, --font-face","option to remove unused font-faces").option("-keyframes, --keyframes","option to remove unused keyframes").option("-v, --variables","option to remove unused variables").option("-rejected, --rejected","option to output rejected selectors").option("-rejected-css, --rejected-css","option to output rejected css").option("-s, --safelist <list...>","list of classes that should not be removed").option("-b, --blocklist <list...>","list of selectors that should be removed").option("-k, --skippedContentGlobs <list...>","list of glob patterns for folders/files that should not be scanned"),e.program.parse(process.argv);const{config:s,css:r,content:o,output:i,fontFace:n,keyframes:a,variables:c,rejected:l,rejectedCss:u,safelist:d,blocklist:f,skippedContentGlobs:h}=e.program.opts();s||o&&r||e.program.help();let p=S;s&&(p=await j(s)),o&&(p.content=o),r&&(p.css=r),n&&(p.fontFace=n),a&&(p.keyframes=a),l&&(p.rejected=l),u&&(p.rejectedCss=u),c&&(p.variables=c),d&&(p.safelist=V(d)),f&&(p.blocklist=f),h&&(p.skippedContentGlobs=h);const v=await(new G).purge(p),y=p.output||i;if(y){if(1===v.length&&y.endsWith(".css"))return void await O(y,v[0].css);for(const e of v){const s=null===(t=null==e?void 0:e.file)||void 0===t?void 0:t.split("/").pop();await O(`${i}/${s}`,e.css)}}else console.log(JSON.stringify(v))}()}catch(e){console.error(e.message),process.exit(1)}
2
+ "use strict";var e=require("commander"),t=require("fs"),s=require("glob"),r=require("path"),o=require("postcss"),i=require("postcss-selector-parser"),n=require("util");function a(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function c(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 l=c(t),u=a(t),d=a(s),f=a(r),h=c(o),p=a(i),m="4.1.2",g="Remove unused css selectors";function v(e,t){t&&t.forEach(e.add,e)}class y{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)?v(this.undetermined,e):e instanceof y?(v(this.undetermined,e.undetermined),v(this.attrNames,e.attrNames),v(this.attrValues,e.attrValues),v(this.classes,e.classes),v(this.ids,e.ids),v(this.tags,e.tags)):(v(this.undetermined,e.undetermined),e.attributes&&(v(this.attrNames,e.attributes.names),v(this.attrValues,e.attributes.values)),v(this.classes,e.classes),v(this.ids,e.ids),v(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 b=["*",":root",":after",":before"],S={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 w(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 k{constructor(e){this.nodes=[],this.isUsed=!1,this.value=e}}class F{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 k(e),r=this.nodes.get(t)||[];this.nodes.set(t,[...r,s])}else{const s=new k(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){w(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 A={access:n.promisify(l.access),readFile:n.promisify(l.readFile)};function V(e=[]){return Array.isArray(e)?{...S.safelist,standard:e}:{...S.safelist,...e}}async function j(e="purgecss.config.js"){let t;try{const s=f.default.resolve(process.cwd(),e);t=await function(e){return Promise.resolve().then((function(){return c(require(e))}))}(s)}catch(e){throw new Error(`Error loading the config file ${e.message}`)}return{...S,...t,safelist:V(t.safelist)}}async function x(e,t){return new y(await t(e))}function C(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 U(e){return e.replace(/(^["'])|(["']$)/g,"")}function R(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 E(e,t){return t.hasId(e.value)}function N(e,t){return t.hasTag(e.value)}function P(e){return"atrule"===(null==e?void 0:e.type)}function q(e){return"rule"===(null==e?void 0:e.type)}class G{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 F,this.options=S}collectDeclarationsData(e){const{prop:t,value:s}=e;if(this.options.variables){const r=w(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=U(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 y([]);for(const r of e){let e=[];try{await A.access(r,l.constants.F_OK),e.push(r)}catch(t){e=d.default.sync(r,{nodir:!0,ignore:this.options.skippedContentGlobs})}for(const r of e){const e=await A.readFile(r,"utf-8"),o=this.getFileExtractor(r,t),i=await x(e,o);s.merge(i)}}return s}async extractSelectorsFromString(e,t){const s=new y([]);for(const{raw:r,extension:o}of e){const e=this.getFileExtractor(`.${o}`,t),i=await x(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:U(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)&&C(s,"next"))return void s.remove();if(e.parent&&P(e.parent)&&e.parent.name.endsWith("keyframes"))return;if(!q(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=p.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&&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 i=e.parent;if(e.selector||e.remove(),function(e){return!!(q(e)&&!e.selector||(null==e?void 0:e.nodes)&&!e.nodes.length||P(e)&&(!e.nodes&&!e.params||!e.params&&e.nodes&&!e.nodes.length))}(i)&&(null==i||i.remove()),this.options.rejectedCss&&o.length>0){const t=e.clone(),s=null==i?void 0:i.clone().removeAll().append(t);t.selectors=o;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(...d.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 A.readFile(e,"utf-8"):e.raw,o=h.parse(r);this.walkThroughCSS(o,t),this.options.fontFace&&this.removeUnusedFontFaces(),this.options.keyframes&&this.removeUnusedKeyframes(),this.options.variables&&this.removeUnusedCSSVariables();const i={css:o.toString(),file:"string"==typeof e?e:e.name};this.options.rejected&&(i.rejected=Array.from(this.selectorsRemoved),this.selectorsRemoved.clear()),this.options.rejectedCss&&(i.rejectedCss=h.root({nodes:this.removedNodes}).toString()),s.push(i)}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 b.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 j(e):{...S,...e,safelist:V(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)),n=t.filter((e=>"object"==typeof e)),a=await this.extractSelectorsFromFiles(i,r),c=await this.extractSelectorsFromString(n,r);return this.getPurgedCSS(s,function(...e){const t=new y([]);return e.forEach(t.merge,t),t}(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 o of e.nodes){const e=this.getSelectorValue(o);if(e&&this.isSelectorSafelistedDeep(e))return!0;if(e&&(b.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)||R(o,t);break;case"class":r=o,s=t.hasClass(r.value);break;case"id":s=E(o,t);break;case"tag":s=N(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&&(C(e,"start")?(this.ignore=!0,e.remove()):C(e,"end")&&(this.ignore=!1,e.remove())))))}}async function O(e,t){try{await u.default.promises.writeFile(e,t)}catch(e){console.error(e.message)}}try{!async function(){var t;e.program.description(g).version(m).usage("--css <css...> --content <content...> [options]"),e.program.option("-con, --content <files...>","glob of content files").option("-css, --css <files...>","glob of css files").option("-c, --config <path>","path to the configuration file").option("-o, --output <path>","file path directory to write purged css files to").option("-font, --font-face","option to remove unused font-faces").option("-keyframes, --keyframes","option to remove unused keyframes").option("-v, --variables","option to remove unused variables").option("-rejected, --rejected","option to output rejected selectors").option("-rejected-css, --rejected-css","option to output rejected css").option("-s, --safelist <list...>","list of classes that should not be removed").option("-b, --blocklist <list...>","list of selectors that should be removed").option("-k, --skippedContentGlobs <list...>","list of glob patterns for folders/files that should not be scanned"),e.program.parse(process.argv);const{config:s,css:r,content:o,output:i,fontFace:n,keyframes:a,variables:c,rejected:l,rejectedCss:u,safelist:d,blocklist:f,skippedContentGlobs:h}=e.program.opts();s||o&&r||e.program.help();let p=S;s&&(p=await j(s)),o&&(p.content=o),r&&(p.css=r),n&&(p.fontFace=n),a&&(p.keyframes=a),l&&(p.rejected=l),u&&(p.rejectedCss=u),c&&(p.variables=c),d&&(p.safelist=V(d)),f&&(p.blocklist=f),h&&(p.skippedContentGlobs=h);const v=await(new G).purge(p),y=p.output||i;if(y){if(1===v.length&&y.endsWith(".css"))return void await O(y,v[0].css);for(const e of v){const s=null===(t=null==e?void 0:e.file)||void 0===t?void 0:t.split("/").pop();await O(`${y}/${s}`,e.css)}}else console.log(JSON.stringify(v))}()}catch(e){console.error(e.message),process.exit(1)}
package/lib/purgecss.d.ts CHANGED
@@ -1,109 +1,111 @@
1
1
  import * as postcss from "postcss";
2
2
  type PostCSSRoot = postcss.Root;
3
3
  interface AtRules {
4
- fontFace: Array<{
5
- name: string;
6
- node: postcss.AtRule;
7
- }>;
8
- keyframes: postcss.AtRule[];
4
+ fontFace: Array<{
5
+ name: string;
6
+ node: postcss.AtRule;
7
+ }>;
8
+ keyframes: postcss.AtRule[];
9
9
  }
10
10
  interface RawContent<T = string> {
11
- extension: string;
12
- raw: T;
11
+ extension: string;
12
+ raw: T;
13
13
  }
14
14
  interface RawCSS {
15
- raw: string;
16
- name?: string;
15
+ raw: string;
16
+ name?: string;
17
17
  }
18
18
  interface ExtractorResultDetailed {
19
- attributes: {
20
- names: string[];
21
- values: string[];
22
- };
23
- classes: string[];
24
- ids: string[];
25
- tags: string[];
26
- undetermined: string[];
19
+ attributes: {
20
+ names: string[];
21
+ values: string[];
22
+ };
23
+ classes: string[];
24
+ ids: string[];
25
+ tags: string[];
26
+ undetermined: string[];
27
27
  }
28
28
  type ExtractorResult = ExtractorResultDetailed | string[];
29
29
  type ExtractorFunction<T = string> = (content: T) => ExtractorResult;
30
30
  interface Extractors {
31
- extensions: string[];
32
- extractor: ExtractorFunction;
31
+ extensions: string[];
32
+ extractor: ExtractorFunction;
33
33
  }
34
34
  type IgnoreType = "end" | "start" | "next";
35
35
  type StringRegExpArray = Array<RegExp | string>;
36
36
  type ComplexSafelist = {
37
- standard?: StringRegExpArray;
38
- deep?: RegExp[];
39
- greedy?: RegExp[];
40
- variables?: StringRegExpArray;
41
- keyframes?: StringRegExpArray;
37
+ standard?: StringRegExpArray;
38
+ deep?: RegExp[];
39
+ greedy?: RegExp[];
40
+ variables?: StringRegExpArray;
41
+ keyframes?: StringRegExpArray;
42
42
  };
43
43
  type UserDefinedSafelist = StringRegExpArray | ComplexSafelist;
44
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[];
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
61
  }
62
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[];
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
79
  }
80
80
  interface ResultPurge {
81
- css: string;
82
- rejectedCss?: string;
83
- file?: string;
84
- rejected?: string[];
81
+ css: string;
82
+ rejectedCss?: string;
83
+ file?: string;
84
+ rejected?: string[];
85
85
  }
86
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;
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
104
  }
105
105
  declare const defaultOptions: Options;
106
- declare function standardizeSafelist(userDefinedSafelist?: UserDefinedSafelist): Required<ComplexSafelist>;
106
+ declare function standardizeSafelist(
107
+ userDefinedSafelist?: UserDefinedSafelist
108
+ ): Required<ComplexSafelist>;
107
109
  /**
108
110
  * Load the configuration file from the path
109
111
  * @param configFile Path of the config file
@@ -114,184 +116,219 @@ declare function setOptions(configFile?: string): Promise<Options>;
114
116
  * @param extractorSelectorsA extractor selectors A
115
117
  * @param extractorSelectorsB extractor selectors B
116
118
  */
117
- declare function mergeExtractorSelectors(...extractors: (ExtractorResultDetailed | ExtractorResultSets)[]): ExtractorResultSets;
119
+ declare function mergeExtractorSelectors(
120
+ ...extractors: (ExtractorResultDetailed | ExtractorResultSets)[]
121
+ ): ExtractorResultSets;
118
122
  declare class PurgeCSS {
119
- private ignore;
120
- private atRules;
121
- private usedAnimations;
122
- private usedFontFaces;
123
- selectorsRemoved: Set<string>;
124
- removedNodes: postcss.Node[];
125
- private variablesStructure;
126
- options: Options;
127
- private collectDeclarationsData;
128
- /**
129
- * Get the extractor corresponding to the extension file
130
- * @param filename Name of the file
131
- * @param extractors Array of extractors definition
132
- */
133
- /**
134
- * Get the extractor corresponding to the extension file
135
- * @param filename Name of the file
136
- * @param extractors Array of extractors definition
137
- */
138
- private getFileExtractor;
139
- /**
140
- * Extract the selectors present in the files using a purgecss extractor
141
- * @param files Array of files path or glob pattern
142
- * @param extractors Array of extractors
143
- */
144
- /**
145
- * Extract the selectors present in the files using a purgecss extractor
146
- * @param files Array of files path or glob pattern
147
- * @param extractors Array of extractors
148
- */
149
- extractSelectorsFromFiles(files: string[], extractors: Extractors[]): Promise<ExtractorResultSets>;
150
- /**
151
- * Extract the selectors present in the passed string using a PurgeCSS extractor
152
- * @param content Array of content
153
- * @param extractors Array of extractors
154
- */
155
- /**
156
- * Extract the selectors present in the passed string using a PurgeCSS extractor
157
- * @param content Array of content
158
- * @param extractors Array of extractors
159
- */
160
- extractSelectorsFromString(content: RawContent[], extractors: Extractors[]): Promise<ExtractorResultSets>;
161
- /**
162
- * Evaluate at-rule and register it for future reference
163
- * @param node node of postcss AST
164
- */
165
- /**
166
- * Evaluate at-rule and register it for future reference
167
- * @param node node of postcss AST
168
- */
169
- private evaluateAtRule;
170
- /**
171
- * Evaluate css selector and decide if it should be removed or not
172
- * @param node node of postcss AST
173
- * @param selectors selectors used in content files
174
- */
175
- /**
176
- * Evaluate css selector and decide if it should be removed or not
177
- * @param node node of postcss AST
178
- * @param selectors selectors used in content files
179
- */
180
- private evaluateRule;
181
- /**
182
- * Get the purged version of the css based on the files
183
- * @param cssOptions css options, files or raw strings
184
- * @param selectors set of extracted css selectors
185
- */
186
- /**
187
- * Get the purged version of the css based on the files
188
- * @param cssOptions css options, files or raw strings
189
- * @param selectors set of extracted css selectors
190
- */
191
- getPurgedCSS(cssOptions: Array<string | RawCSS>, selectors: ExtractorResultSets): Promise<ResultPurge[]>;
192
- /**
193
- * Check if the keyframe is safelisted with the option safelist keyframes
194
- * @param keyframesName name of the keyframe animation
195
- */
196
- /**
197
- * Check if the keyframe is safelisted with the option safelist keyframes
198
- * @param keyframesName name of the keyframe animation
199
- */
200
- private isKeyframesSafelisted;
201
- /**
202
- * Check if the selector is blocklisted with the option blocklist
203
- * @param selector css selector
204
- */
205
- /**
206
- * Check if the selector is blocklisted with the option blocklist
207
- * @param selector css selector
208
- */
209
- private isSelectorBlocklisted;
210
- /**
211
- * Check if the selector is safelisted with the option safelist standard
212
- * @param selector css selector
213
- */
214
- /**
215
- * Check if the selector is safelisted with the option safelist standard
216
- * @param selector css selector
217
- */
218
- private isSelectorSafelisted;
219
- /**
220
- * Check if the selector is safelisted with the option safelist deep
221
- * @param selector selector
222
- */
223
- /**
224
- * Check if the selector is safelisted with the option safelist deep
225
- * @param selector selector
226
- */
227
- private isSelectorSafelistedDeep;
228
- /**
229
- * Check if the selector is safelisted with the option safelist greedy
230
- * @param selector selector
231
- */
232
- /**
233
- * Check if the selector is safelisted with the option safelist greedy
234
- * @param selector selector
235
- */
236
- private isSelectorSafelistedGreedy;
237
- /**
238
- * Remove unused css
239
- * @param userOptions PurgeCSS options
240
- */
241
- /**
242
- * Remove unused css
243
- * @param userOptions PurgeCSS options
244
- */
245
- purge(userOptions: UserDefinedOptions | string | undefined): Promise<ResultPurge[]>;
246
- /**
247
- * Remove unused CSS variables
248
- */
249
- /**
250
- * Remove unused CSS variables
251
- */
252
- removeUnusedCSSVariables(): void;
253
- /**
254
- * Remove unused font-faces
255
- */
256
- /**
257
- * Remove unused font-faces
258
- */
259
- removeUnusedFontFaces(): void;
260
- /**
261
- * Remove unused keyframes
262
- */
263
- /**
264
- * Remove unused keyframes
265
- */
266
- removeUnusedKeyframes(): void;
267
- /**
268
- * Transform a selector node into a string
269
- */
270
- /**
271
- * Transform a selector node into a string
272
- */
273
- private getSelectorValue;
274
- /**
275
- * Determine if the selector should be kept, based on the selectors found in the files
276
- * @param selector set of css selectors found in the content files or string
277
- * @param selectorsFromExtractor selectors in the css rule
278
- */
279
- /**
280
- * Determine if the selector should be kept, based on the selectors found in the files
281
- * @param selector set of css selectors found in the content files or string
282
- * @param selectorsFromExtractor selectors in the css rule
283
- */
284
- private shouldKeepSelector;
285
- /**
286
- * Walk through the CSS AST and remove unused CSS
287
- * @param root root node of the postcss AST
288
- * @param selectors selectors used in content files
289
- */
290
- /**
291
- * Walk through the CSS AST and remove unused CSS
292
- * @param root root node of the postcss AST
293
- * @param selectors selectors used in content files
294
- */
295
- walkThroughCSS(root: PostCSSRoot, selectors: ExtractorResultSets): void;
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;
296
311
  }
297
- export { PurgeCSS as default, PurgeCSS, defaultOptions, PostCSSRoot, AtRules, RawContent, RawCSS, ExtractorResultDetailed, ExtractorResult, ExtractorFunction, Extractors, IgnoreType, StringRegExpArray, ComplexSafelist, UserDefinedSafelist, UserDefinedOptions, Options, ResultPurge, standardizeSafelist, setOptions, mergeExtractorSelectors };
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
+ };
@@ -1,109 +1,111 @@
1
1
  import * as postcss from "postcss";
2
2
  type PostCSSRoot = postcss.Root;
3
3
  interface AtRules {
4
- fontFace: Array<{
5
- name: string;
6
- node: postcss.AtRule;
7
- }>;
8
- keyframes: postcss.AtRule[];
4
+ fontFace: Array<{
5
+ name: string;
6
+ node: postcss.AtRule;
7
+ }>;
8
+ keyframes: postcss.AtRule[];
9
9
  }
10
10
  interface RawContent<T = string> {
11
- extension: string;
12
- raw: T;
11
+ extension: string;
12
+ raw: T;
13
13
  }
14
14
  interface RawCSS {
15
- raw: string;
16
- name?: string;
15
+ raw: string;
16
+ name?: string;
17
17
  }
18
18
  interface ExtractorResultDetailed {
19
- attributes: {
20
- names: string[];
21
- values: string[];
22
- };
23
- classes: string[];
24
- ids: string[];
25
- tags: string[];
26
- undetermined: string[];
19
+ attributes: {
20
+ names: string[];
21
+ values: string[];
22
+ };
23
+ classes: string[];
24
+ ids: string[];
25
+ tags: string[];
26
+ undetermined: string[];
27
27
  }
28
28
  type ExtractorResult = ExtractorResultDetailed | string[];
29
29
  type ExtractorFunction<T = string> = (content: T) => ExtractorResult;
30
30
  interface Extractors {
31
- extensions: string[];
32
- extractor: ExtractorFunction;
31
+ extensions: string[];
32
+ extractor: ExtractorFunction;
33
33
  }
34
34
  type IgnoreType = "end" | "start" | "next";
35
35
  type StringRegExpArray = Array<RegExp | string>;
36
36
  type ComplexSafelist = {
37
- standard?: StringRegExpArray;
38
- deep?: RegExp[];
39
- greedy?: RegExp[];
40
- variables?: StringRegExpArray;
41
- keyframes?: StringRegExpArray;
37
+ standard?: StringRegExpArray;
38
+ deep?: RegExp[];
39
+ greedy?: RegExp[];
40
+ variables?: StringRegExpArray;
41
+ keyframes?: StringRegExpArray;
42
42
  };
43
43
  type UserDefinedSafelist = StringRegExpArray | ComplexSafelist;
44
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[];
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
61
  }
62
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[];
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
79
  }
80
80
  interface ResultPurge {
81
- css: string;
82
- rejectedCss?: string;
83
- file?: string;
84
- rejected?: string[];
81
+ css: string;
82
+ rejectedCss?: string;
83
+ file?: string;
84
+ rejected?: string[];
85
85
  }
86
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;
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
104
  }
105
105
  declare const defaultOptions: Options;
106
- declare function standardizeSafelist(userDefinedSafelist?: UserDefinedSafelist): Required<ComplexSafelist>;
106
+ declare function standardizeSafelist(
107
+ userDefinedSafelist?: UserDefinedSafelist
108
+ ): Required<ComplexSafelist>;
107
109
  /**
108
110
  * Load the configuration file from the path
109
111
  * @param configFile Path of the config file
@@ -114,184 +116,219 @@ declare function setOptions(configFile?: string): Promise<Options>;
114
116
  * @param extractorSelectorsA extractor selectors A
115
117
  * @param extractorSelectorsB extractor selectors B
116
118
  */
117
- declare function mergeExtractorSelectors(...extractors: (ExtractorResultDetailed | ExtractorResultSets)[]): ExtractorResultSets;
119
+ declare function mergeExtractorSelectors(
120
+ ...extractors: (ExtractorResultDetailed | ExtractorResultSets)[]
121
+ ): ExtractorResultSets;
118
122
  declare class PurgeCSS {
119
- private ignore;
120
- private atRules;
121
- private usedAnimations;
122
- private usedFontFaces;
123
- selectorsRemoved: Set<string>;
124
- removedNodes: postcss.Node[];
125
- private variablesStructure;
126
- options: Options;
127
- private collectDeclarationsData;
128
- /**
129
- * Get the extractor corresponding to the extension file
130
- * @param filename Name of the file
131
- * @param extractors Array of extractors definition
132
- */
133
- /**
134
- * Get the extractor corresponding to the extension file
135
- * @param filename Name of the file
136
- * @param extractors Array of extractors definition
137
- */
138
- private getFileExtractor;
139
- /**
140
- * Extract the selectors present in the files using a purgecss extractor
141
- * @param files Array of files path or glob pattern
142
- * @param extractors Array of extractors
143
- */
144
- /**
145
- * Extract the selectors present in the files using a purgecss extractor
146
- * @param files Array of files path or glob pattern
147
- * @param extractors Array of extractors
148
- */
149
- extractSelectorsFromFiles(files: string[], extractors: Extractors[]): Promise<ExtractorResultSets>;
150
- /**
151
- * Extract the selectors present in the passed string using a PurgeCSS extractor
152
- * @param content Array of content
153
- * @param extractors Array of extractors
154
- */
155
- /**
156
- * Extract the selectors present in the passed string using a PurgeCSS extractor
157
- * @param content Array of content
158
- * @param extractors Array of extractors
159
- */
160
- extractSelectorsFromString(content: RawContent[], extractors: Extractors[]): Promise<ExtractorResultSets>;
161
- /**
162
- * Evaluate at-rule and register it for future reference
163
- * @param node node of postcss AST
164
- */
165
- /**
166
- * Evaluate at-rule and register it for future reference
167
- * @param node node of postcss AST
168
- */
169
- private evaluateAtRule;
170
- /**
171
- * Evaluate css selector and decide if it should be removed or not
172
- * @param node node of postcss AST
173
- * @param selectors selectors used in content files
174
- */
175
- /**
176
- * Evaluate css selector and decide if it should be removed or not
177
- * @param node node of postcss AST
178
- * @param selectors selectors used in content files
179
- */
180
- private evaluateRule;
181
- /**
182
- * Get the purged version of the css based on the files
183
- * @param cssOptions css options, files or raw strings
184
- * @param selectors set of extracted css selectors
185
- */
186
- /**
187
- * Get the purged version of the css based on the files
188
- * @param cssOptions css options, files or raw strings
189
- * @param selectors set of extracted css selectors
190
- */
191
- getPurgedCSS(cssOptions: Array<string | RawCSS>, selectors: ExtractorResultSets): Promise<ResultPurge[]>;
192
- /**
193
- * Check if the keyframe is safelisted with the option safelist keyframes
194
- * @param keyframesName name of the keyframe animation
195
- */
196
- /**
197
- * Check if the keyframe is safelisted with the option safelist keyframes
198
- * @param keyframesName name of the keyframe animation
199
- */
200
- private isKeyframesSafelisted;
201
- /**
202
- * Check if the selector is blocklisted with the option blocklist
203
- * @param selector css selector
204
- */
205
- /**
206
- * Check if the selector is blocklisted with the option blocklist
207
- * @param selector css selector
208
- */
209
- private isSelectorBlocklisted;
210
- /**
211
- * Check if the selector is safelisted with the option safelist standard
212
- * @param selector css selector
213
- */
214
- /**
215
- * Check if the selector is safelisted with the option safelist standard
216
- * @param selector css selector
217
- */
218
- private isSelectorSafelisted;
219
- /**
220
- * Check if the selector is safelisted with the option safelist deep
221
- * @param selector selector
222
- */
223
- /**
224
- * Check if the selector is safelisted with the option safelist deep
225
- * @param selector selector
226
- */
227
- private isSelectorSafelistedDeep;
228
- /**
229
- * Check if the selector is safelisted with the option safelist greedy
230
- * @param selector selector
231
- */
232
- /**
233
- * Check if the selector is safelisted with the option safelist greedy
234
- * @param selector selector
235
- */
236
- private isSelectorSafelistedGreedy;
237
- /**
238
- * Remove unused css
239
- * @param userOptions PurgeCSS options
240
- */
241
- /**
242
- * Remove unused css
243
- * @param userOptions PurgeCSS options
244
- */
245
- purge(userOptions: UserDefinedOptions | string | undefined): Promise<ResultPurge[]>;
246
- /**
247
- * Remove unused CSS variables
248
- */
249
- /**
250
- * Remove unused CSS variables
251
- */
252
- removeUnusedCSSVariables(): void;
253
- /**
254
- * Remove unused font-faces
255
- */
256
- /**
257
- * Remove unused font-faces
258
- */
259
- removeUnusedFontFaces(): void;
260
- /**
261
- * Remove unused keyframes
262
- */
263
- /**
264
- * Remove unused keyframes
265
- */
266
- removeUnusedKeyframes(): void;
267
- /**
268
- * Transform a selector node into a string
269
- */
270
- /**
271
- * Transform a selector node into a string
272
- */
273
- private getSelectorValue;
274
- /**
275
- * Determine if the selector should be kept, based on the selectors found in the files
276
- * @param selector set of css selectors found in the content files or string
277
- * @param selectorsFromExtractor selectors in the css rule
278
- */
279
- /**
280
- * Determine if the selector should be kept, based on the selectors found in the files
281
- * @param selector set of css selectors found in the content files or string
282
- * @param selectorsFromExtractor selectors in the css rule
283
- */
284
- private shouldKeepSelector;
285
- /**
286
- * Walk through the CSS AST and remove unused CSS
287
- * @param root root node of the postcss AST
288
- * @param selectors selectors used in content files
289
- */
290
- /**
291
- * Walk through the CSS AST and remove unused CSS
292
- * @param root root node of the postcss AST
293
- * @param selectors selectors used in content files
294
- */
295
- walkThroughCSS(root: PostCSSRoot, selectors: ExtractorResultSets): void;
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;
296
311
  }
297
- export { PurgeCSS as default, PurgeCSS, defaultOptions, PostCSSRoot, AtRules, RawContent, RawCSS, ExtractorResultDetailed, ExtractorResult, ExtractorFunction, Extractors, IgnoreType, StringRegExpArray, ComplexSafelist, UserDefinedSafelist, UserDefinedOptions, Options, ResultPurge, standardizeSafelist, setOptions, mergeExtractorSelectors };
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
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "purgecss",
3
- "version": "4.1.2",
3
+ "version": "4.1.3",
4
4
  "description": "Remove unused css selectors",
5
5
  "author": "Ffloriel",
6
6
  "homepage": "https://purgecss.com",
@@ -54,5 +54,5 @@
54
54
  "access": "public",
55
55
  "registry": "https://registry.npmjs.org/"
56
56
  },
57
- "gitHead": "1329d96b0ad17e9b2b4d604d1a689856da176a59"
57
+ "gitHead": "37e5053a446880d12fd2f55abfc362c3dac9c49c"
58
58
  }