purgecss 5.0.0 → 6.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.
- package/README.md +5 -5
- package/bin/purgecss.js +1 -1
- package/lib/purgecss.d.ts +27 -21
- package/lib/purgecss.esm.js +1 -1
- package/lib/purgecss.js +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ This is where PurgeCSS comes into play. PurgeCSS analyzes your content and your
|
|
|
19
19
|
## Sponsors 🥰
|
|
20
20
|
|
|
21
21
|
[<img src="https://avatars0.githubusercontent.com/u/67109815?v=4" height="85" style="margin-right: 10px">](https://tailwindcss.com)
|
|
22
|
-
[<img src="https://avatars.githubusercontent.com/u/
|
|
22
|
+
[<img src="https://avatars.githubusercontent.com/u/133211198?v=4" height="85" style="margin-right: 10px">](https://www.bairesdev.com/sponsoring-open-source-projects/)
|
|
23
23
|
|
|
24
24
|
## Documentation
|
|
25
25
|
|
|
@@ -63,11 +63,11 @@ npm i --save-dev purgecss
|
|
|
63
63
|
## Usage
|
|
64
64
|
|
|
65
65
|
```js
|
|
66
|
-
import PurgeCSS from
|
|
66
|
+
import PurgeCSS from "purgecss";
|
|
67
67
|
const purgeCSSResults = await new PurgeCSS().purge({
|
|
68
|
-
content: [
|
|
69
|
-
css: [
|
|
70
|
-
})
|
|
68
|
+
content: ["**/*.html"],
|
|
69
|
+
css: ["**/*.css"],
|
|
70
|
+
});
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
## Contributing
|
package/bin/purgecss.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});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 u=c(t),l=c(s),d=c(r),f=c(o),h=a(i),p="4.1.3",m="Remove unused css selectors";function g(e,t){t&&t.forEach(e.add,e)}class v{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)?g(this.undetermined,e):e instanceof v?(g(this.undetermined,e.undetermined),g(this.attrNames,e.attrNames),g(this.attrValues,e.attrValues),g(this.classes,e.classes),g(this.ids,e.ids),g(this.tags,e.tags)):(g(this.undetermined,e.undetermined),e.attributes&&(g(this.attrNames,e.attributes.names),g(this.attrValues,e.attributes.values)),g(this.classes,e.classes),g(this.ids,e.ids),g(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 y=["*",":root",":after",":before"],b={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 S(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 w{constructor(e){this.nodes=[],this.isUsed=!1,this.value=e}}class k{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 w(e),r=this.nodes.get(t)||[];this.nodes.set(t,[...r,s])}else{const s=new w(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){S(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:n.promisify(u.access),readFile:n.promisify(u.readFile)};function x(e=[]){return Array.isArray(e)?{...b.safelist,standard:e}:{...b.safelist,...e}}async function A(e="purgecss.config.js"){let t;try{const s=d.resolve(process.cwd(),e);t=await function(e){return Promise.resolve().then((function(){return c(require(e))}))}(s)}catch(e){if(e instanceof Error)throw new Error(`Error loading the config file ${e.message}`);throw new Error}return{...b,...t,safelist:x(t.safelist)}}async function V(e,t){return new v(await t(e))}function j(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 C(e){return e.replace(/(^["'])|(["']$)/g,"")}function U(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 R(e,t){return t.hasTag(e.value)}function N(e){return"atrule"===(null==e?void 0:e.type)}function O(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 k,this.options=b}collectDeclarationsData(e){const{prop:t,value:s}=e;if(this.options.variables){const r=S(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=C(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 v([]);for(const r of e){let e=[];try{await F.access(r,u.constants.F_OK),e.push(r)}catch(t){e=l.sync(r,{nodir:!0,ignore:this.options.skippedContentGlobs})}for(const r of e){const e=await F.readFile(r,"utf-8"),o=this.getFileExtractor(r,t),i=await V(e,o);s.merge(i)}}return s}async extractSelectorsFromString(e,t){const s=new v([]);for(const{raw:r,extension:o}of e){const e=this.getFileExtractor(`.${o}`,t),i=await V(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:C(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)&&j(s,"next"))return void s.remove();if(e.parent&&N(e.parent)&&e.parent.name.endsWith("keyframes"))return;if(!O(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=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&&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!!(O(e)&&!e.selector||(null==e?void 0:e.nodes)&&!e.nodes.length||N(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){var s;const r=[],o=[];for(const t of e)"string"==typeof t?o.push(...l.sync(t,{nodir:!0,ignore:this.options.skippedContentGlobs})):o.push(t);for(const e of o){const o="string"==typeof e?this.options.stdin?e:await F.readFile(e,"utf-8"):e.raw,i="string"==typeof e&&!this.options.stdin,n=f.parse(o,{from:i?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=f.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 y.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 A(e):{...b,...e,safelist:x(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 v([]);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&&(y.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)||U(o,t);break;case"class":r=o,s=t.hasClass(r.value);break;case"id":s=E(o,t);break;case"tag":s=R(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&&(j(e,"start")?(this.ignore=!0,e.remove()):j(e,"end")&&(this.ignore=!1,e.remove())))))}}async function M(e,t){try{await u.promises.writeFile(e,t)}catch(e){e instanceof Error&&console.error(e.message)}}async function q(e){const t=[];for await(const s of e)t.push(s);return Buffer.concat(t).toString("utf8")}function G(e){return e.description(m).version(p).usage("--css <css...> --content <content...> [options]"),e.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}async function W(e){const{config:t,css:s,content:r,output:o,fontFace:i,keyframes:n,variables:a,rejected:c,rejectedCss:u,safelist:l,blocklist:d,skippedContentGlobs:f}=e.opts();t||r&&s||e.help();let h=b;return t&&(h=await A(t)),r&&(1===r.length&&"-"===r[0]?h.content=[{raw:await q(process.stdin),extension:""}]:h.content=r),s&&(1===s.length&&"-"===s[0]?h.css=[{raw:await q(process.stdin)}]:h.css=s),i&&(h.fontFace=i),n&&(h.keyframes=n),c&&(h.rejected=c),u&&(h.rejectedCss=u),a&&(h.variables=a),l&&(h.safelist=x(l)),d&&(h.blocklist=d),f&&(h.skippedContentGlobs=f),o&&(h.output=o),h}async function D(e){var t;const s=await W(e),r=await(new P).purge(s);if(s.output){if(1===r.length&&s.output.endsWith(".css"))return void await M(s.output,r[0].css);for(const e of r){const r=null===(t=null==e?void 0:e.file)||void 0===t?void 0:t.split("/").pop();await M(`${s.output}/${r}`,e.css)}}else console.log(JSON.stringify(r))}async function K(){try{const t=G(new e.Command);t.parse(process.argv),D(t)}catch(e){e instanceof Error&&console.error(e.message),process.exit(1)}}exports.getOptions=W,exports.main=K,exports.parseCommandOptions=G,exports.run=D,K();
|
|
2
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});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 u=c(t),l=c(s),d=c(r),f=c(o),h=a(i),p={name:"purgecss",version:"6.0.0",description:"Remove unused css selectors",author:"Ffloriel",homepage:"https://purgecss.com",keywords:["optimize","optimization","remove","unused","css","html","rules","purge","uncss","purify"],license:"MIT",main:"lib/purgecss.js",module:"./lib/purgecss.esm.js",types:"./lib/purgecss.d.ts",bin:{purgecss:"bin/purgecss.js"},directories:{lib:"lib",test:"__tests__"},files:["bin","lib"],repository:{type:"git",url:"git+https://github.com/FullHuman/purgecss.git"},scripts:{build:"ts-node build.ts",test:"jest"},dependencies:{commander:"^12.0.0",glob:"^10.3.10",postcss:"^8.4.4","postcss-selector-parser":"^6.0.7"},devDependencies:{"@types/glob":"^8.0.0"},bugs:{url:"https://github.com/FullHuman/purgecss/issues"},publishConfig:{access:"public",registry:"https://registry.npmjs.org/"}};const m="purgecss.config.js",g="Error loading the config file";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,sourceMap:!1,stdin:!1,stdout:!1,variables:!1,safelist:{standard:[],deep:[],greedy:[],variables:[],keyframes:[]},blocklist:[],skippedContentGlobs:[],dynamicAttributes:[]};class w{constructor(e){this.nodes=[],this.isUsed=!1,this.value=e}}class k{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 w(e),r=this.nodes.get(t)||[];this.nodes.set(t,[...r,s])}else{const s=new w(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){const t=e.value.value.matchAll(/var\((.+?)[,)]/g);for(const e of t)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:n.promisify(u.access),readFile:n.promisify(u.readFile)};function j(e=[]){return Array.isArray(e)?{...S.safelist,standard:e}:{...S.safelist,...e}}async function A(e=m){let t;try{const s=d.resolve(process.cwd(),e);t=await function(e){return Promise.resolve().then((function(){return c(require(e))}))}(s)}catch(e){if(e instanceof Error)throw new Error(`${g} ${e.message}`);throw new Error}return{...S,...t,safelist:j(t.safelist)}}async function x(e,t){return new y(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 C(e){return e.replace(/(^["'])|(["']$)/g,"")}function U(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 R(e,t){return t.hasTag(e.value)}function N(e){return"atrule"===(null==e?void 0:e.type)}function O(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 k,this.options=S}collectDeclarationsData(e){const{prop:t,value:s}=e;if(this.options.variables){const r=s.matchAll(/var\((.+?)[,)]/g);t.startsWith("--")?(this.variablesStructure.addVariable(e),this.variablesStructure.addVariableUsage(e,r)):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=C(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([]),r=[];for(const t of e)try{await F.access(t,u.constants.F_OK),r.push(t)}catch(e){r.push(...l.sync(t,{nodir:!0,ignore:this.options.skippedContentGlobs.map((e=>e.replace(/^\.\//,"")))}))}e.length>0&&0===r.length&&console.warn("No files found from the passed PurgeCSS option 'content'.");for(const e of r){const r=await F.readFile(e,"utf-8"),o=this.getFileExtractor(e,t),i=await x(r,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:C(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&&N(e.parent)&&e.parent.name.endsWith("keyframes"))return;if(!O(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;const r=[];if(e.selector=h.default((e=>{e.walk((e=>{if("selector"!==e.type)return;this.shouldKeepSelector(e,t)||(this.options.rejected&&this.selectorsRemoved.add(e.toString()),this.options.rejectedCss&&r.push(e.toString()),e.remove())})),e.walk((e=>{"selector"===e.type&&e.toString()&&/(:where)|(:is)/.test(e.toString())&&e.walk((t=>{"pseudo"===t.type&&(":where"!==t.value&&":is"!==t.value||0===t.nodes.length&&e.remove())}))}))})).processSync(e.selector),e.selector&&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!!(O(e)&&!e.selector||(null==e?void 0:e.nodes)&&!e.nodes.length||N(e)&&(!e.nodes&&!e.params||!e.params&&e.nodes&&!e.nodes.length))}(o)&&(null==o||o.remove()),this.options.rejectedCss&&r.length>0){const t=e.clone(),s=null==o?void 0:o.clone().removeAll().append(t);t.selectors=r;const i=s||t;this.removedNodes.push(i)}}async getPurgedCSS(e,t){var s;const r=[],o=[];for(const t of e)"string"==typeof t?o.push(...l.sync(t,{nodir:!0,ignore:this.options.skippedContentGlobs})):o.push(t);for(const e of o){const o="string"==typeof e?this.options.stdin?e:await F.readFile(e,"utf-8"):e.raw,i="string"==typeof e&&!this.options.stdin,n=f.parse(o,{from:i?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=f.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 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 A(e):{...S,...e,safelist:j(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)&&!function(e){return e.parent&&"pseudo"===e.parent.type&&(":where"===e.parent.value||":is"===e.parent.value)||!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)||U(o,t);break;case"class":r=o,s=t.hasClass(r.value);break;case"id":s=E(o,t);break;case"tag":s=R(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&&(V(e,"start")?(this.ignore=!0,e.remove()):V(e,"end")&&(this.ignore=!1,e.remove())))))}}async function M(e,t){try{await u.promises.writeFile(e,t)}catch(e){e instanceof Error&&console.error(e.message)}}async function _(e){const t=[];for await(const s of e)t.push(s);return Buffer.concat(t).toString("utf8")}function q(e){return e.description(p.description).version(p.version).usage("--css <css...> --content <content...> [options]"),e.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}async function D(e){const{config:t,css:s,content:r,output:o,fontFace:i,keyframes:n,variables:a,rejected:c,rejectedCss:u,safelist:l,blocklist:d,skippedContentGlobs:f}=e.opts();t||r&&s||e.help();let h=S;return t&&(h=await A(t)),r&&(1===r.length&&"-"===r[0]?h.content=[{raw:await _(process.stdin),extension:""}]:h.content=r),s&&(1===s.length&&"-"===s[0]?h.css=[{raw:await _(process.stdin)}]:h.css=s),i&&(h.fontFace=i),n&&(h.keyframes=n),c&&(h.rejected=c),u&&(h.rejectedCss=u),a&&(h.variables=a),l&&(h.safelist=j(l)),d&&(h.blocklist=d),f&&(h.skippedContentGlobs=f),o&&(h.output=o),h}async function G(e){var t;const s=await D(e),r=await(new P).purge(s);if(s.output){if(1===r.length&&s.output.endsWith(".css"))return void await M(s.output,r[0].css);for(const e of r){const r=null===(t=null==e?void 0:e.file)||void 0===t?void 0:t.split("/").pop();await M(`${s.output}/${r}`,e.css)}}else console.log(JSON.stringify(r))}async function W(){try{const t=q(new e.Command);t.parse(process.argv),G(t)}catch(e){e instanceof Error&&console.error(e.message),process.exit(1)}}exports.getOptions=D,exports.main=W,exports.parseCommandOptions=q,exports.run=G,W();
|
package/lib/purgecss.d.ts
CHANGED
|
@@ -444,41 +444,41 @@ export declare type StringRegExpArray = Array<RegExp | string>;
|
|
|
444
444
|
* @public
|
|
445
445
|
*/
|
|
446
446
|
export declare interface UserDefinedOptions {
|
|
447
|
-
/** {@inheritDoc Options.content} */
|
|
447
|
+
/** {@inheritDoc purgecss#Options.content} */
|
|
448
448
|
content: Array<string | RawContent>;
|
|
449
|
-
/** {@inheritDoc Options.css} */
|
|
449
|
+
/** {@inheritDoc purgecss#Options.css} */
|
|
450
450
|
css: Array<string | RawCSS>;
|
|
451
|
-
/** {@inheritDoc Options.defaultExtractor} */
|
|
451
|
+
/** {@inheritDoc purgecss#Options.defaultExtractor} */
|
|
452
452
|
defaultExtractor?: ExtractorFunction;
|
|
453
|
-
/** {@inheritDoc Options.extractors} */
|
|
453
|
+
/** {@inheritDoc purgecss#Options.extractors} */
|
|
454
454
|
extractors?: Array<Extractors>;
|
|
455
|
-
/** {@inheritDoc Options.fontFace} */
|
|
455
|
+
/** {@inheritDoc purgecss#Options.fontFace} */
|
|
456
456
|
fontFace?: boolean;
|
|
457
|
-
/** {@inheritDoc Options.keyframes} */
|
|
457
|
+
/** {@inheritDoc purgecss#Options.keyframes} */
|
|
458
458
|
keyframes?: boolean;
|
|
459
|
-
/** {@inheritDoc Options.output} */
|
|
459
|
+
/** {@inheritDoc purgecss#Options.output} */
|
|
460
460
|
output?: string;
|
|
461
|
-
/** {@inheritDoc Options.rejected} */
|
|
461
|
+
/** {@inheritDoc purgecss#Options.rejected} */
|
|
462
462
|
rejected?: boolean;
|
|
463
|
-
/** {@inheritDoc Options.rejectedCss} */
|
|
463
|
+
/** {@inheritDoc purgecss#Options.rejectedCss} */
|
|
464
464
|
rejectedCss?: boolean;
|
|
465
|
-
/** {@inheritDoc Options.sourceMap } */
|
|
465
|
+
/** {@inheritDoc purgecss#Options.sourceMap } */
|
|
466
466
|
sourceMap?: boolean | (postcss.SourceMapOptions & {
|
|
467
467
|
to?: string;
|
|
468
468
|
});
|
|
469
|
-
/** {@inheritDoc Options.stdin} */
|
|
469
|
+
/** {@inheritDoc purgecss#Options.stdin} */
|
|
470
470
|
stdin?: boolean;
|
|
471
|
-
/** {@inheritDoc Options.stdout} */
|
|
471
|
+
/** {@inheritDoc purgecss#Options.stdout} */
|
|
472
472
|
stdout?: boolean;
|
|
473
|
-
/** {@inheritDoc Options.variables} */
|
|
473
|
+
/** {@inheritDoc purgecss#Options.variables} */
|
|
474
474
|
variables?: boolean;
|
|
475
|
-
/** {@inheritDoc Options.safelist} */
|
|
475
|
+
/** {@inheritDoc purgecss#Options.safelist} */
|
|
476
476
|
safelist?: UserDefinedSafelist;
|
|
477
|
-
/** {@inheritDoc Options.blocklist} */
|
|
477
|
+
/** {@inheritDoc purgecss#Options.blocklist} */
|
|
478
478
|
blocklist?: StringRegExpArray;
|
|
479
|
-
/** {@inheritDoc Options.skippedContentGlobs} */
|
|
479
|
+
/** {@inheritDoc purgecss#Options.skippedContentGlobs} */
|
|
480
480
|
skippedContentGlobs?: Array<string>;
|
|
481
|
-
/** {@inheritDoc Options.dynamicAttributes} */
|
|
481
|
+
/** {@inheritDoc purgecss#Options.dynamicAttributes} */
|
|
482
482
|
dynamicAttributes?: string[];
|
|
483
483
|
}
|
|
484
484
|
|
|
@@ -487,20 +487,26 @@ export declare interface UserDefinedOptions {
|
|
|
487
487
|
*/
|
|
488
488
|
export declare type UserDefinedSafelist = StringRegExpArray | ComplexSafelist;
|
|
489
489
|
|
|
490
|
-
|
|
490
|
+
/**
|
|
491
|
+
* @public
|
|
492
|
+
*/
|
|
493
|
+
export declare class VariableNode {
|
|
491
494
|
nodes: VariableNode[];
|
|
492
495
|
value: postcss.Declaration;
|
|
493
496
|
isUsed: boolean;
|
|
494
497
|
constructor(declaration: postcss.Declaration);
|
|
495
498
|
}
|
|
496
499
|
|
|
497
|
-
|
|
500
|
+
/**
|
|
501
|
+
* @public
|
|
502
|
+
*/
|
|
503
|
+
export declare class VariablesStructure {
|
|
498
504
|
nodes: Map<string, VariableNode[]>;
|
|
499
505
|
usedVariables: Set<string>;
|
|
500
506
|
safelist: StringRegExpArray;
|
|
501
507
|
addVariable(declaration: postcss.Declaration): void;
|
|
502
|
-
addVariableUsage(declaration: postcss.Declaration, matchedVariables: RegExpMatchArray
|
|
503
|
-
addVariableUsageInProperties(matchedVariables: RegExpMatchArray
|
|
508
|
+
addVariableUsage(declaration: postcss.Declaration, matchedVariables: IterableIterator<RegExpMatchArray>): void;
|
|
509
|
+
addVariableUsageInProperties(matchedVariables: IterableIterator<RegExpMatchArray>): void;
|
|
504
510
|
setAsUsed(variableName: string): void;
|
|
505
511
|
removeUnused(): void;
|
|
506
512
|
isVariablesSafelisted(variable: string): boolean;
|
package/lib/purgecss.esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
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};
|
|
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:[]};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){const t=e.value.value.matchAll(/var\((.+?)[,)]/g);for(const e of t)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 l={access:i(e.access),readFile:i(e.readFile)};function u(e=[]){return Array.isArray(e)?{...c.safelist,standard:e}:{...c.safelist,...e}}async function d(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:u(t.safelist)}}async function h(e,t){return new ExtractorResultSets(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 p(...e){const t=new ExtractorResultSets([]);return e.forEach(t.merge,t),t}function m(e){return e.replace(/(^["'])|(["']$)/g,"")}function g(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 v(e,t){return t.hasId(e.value)}function S(e,t){return t.hasTag(e.value)}function y(e){return"atrule"===(null==e?void 0:e.type)}function b(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=s.matchAll(/var\((.+?)[,)]/g);t.startsWith("--")?(this.variablesStructure.addVariable(e),this.variablesStructure.addVariableUsage(e,r)):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=m(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([]),i=[];for(const r of s)try{await l.access(r,e.constants.F_OK),i.push(r)}catch(e){i.push(...t.sync(r,{nodir:!0,ignore:this.options.skippedContentGlobs.map((e=>e.replace(/^\.\//,"")))}))}s.length>0&&0===i.length&&console.warn("No files found from the passed PurgeCSS option 'content'.");for(const e of i){const t=await l.readFile(e,"utf-8"),s=this.getFileExtractor(e,r),i=await h(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 h(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:m(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&&y(e.parent)&&e.parent.name.endsWith("keyframes"))return;if(!b(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;const r=[];if(e.selector=o((e=>{e.walk((e=>{if("selector"!==e.type)return;this.shouldKeepSelector(e,t)||(this.options.rejected&&this.selectorsRemoved.add(e.toString()),this.options.rejectedCss&&r.push(e.toString()),e.remove())})),e.walk((e=>{"selector"===e.type&&e.toString()&&/(:where)|(:is)/.test(e.toString())&&e.walk((t=>{"pseudo"===t.type&&(":where"!==t.value&&":is"!==t.value||0===t.nodes.length&&e.remove())}))}))})).processSync(e.selector),e.selector&&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!!(b(e)&&!e.selector||(null==e?void 0:e.nodes)&&!e.nodes.length||y(e)&&(!e.nodes&&!e.params||!e.params&&e.nodes&&!e.nodes.length))}(i)&&(null==i||i.remove()),this.options.rejectedCss&&r.length>0){const t=e.clone(),s=null==i?void 0:i.clone().removeAll().append(t);t.selectors=r;const o=s||t;this.removedNodes.push(o)}}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 l.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}),u={css:c.toString(),file:"string"==typeof e?e:e.name};this.options.sourceMap&&(u.sourceMap=null===(o=c.map)||void 0===o?void 0:o.toString()),this.options.rejected&&(u.rejected=Array.from(this.selectorsRemoved),this.selectorsRemoved.clear()),this.options.rejectedCss&&(u.rejectedCss=r.root({nodes:this.removedNodes}).toString()),i.push(u)}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 d(e):{...c,...e,safelist:u(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,p(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)&&!function(e){return e.parent&&"pseudo"===e.parent.type&&(":where"===e.parent.value||":is"===e.parent.value)||!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)||g(o,t);break;case"class":r=o,s=t.hasClass(r.value);break;case"id":s=v(o,t);break;case"tag":s=S(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&&(f(e,"start")?(this.ignore=!0,e.remove()):f(e,"end")&&(this.ignore=!1,e.remove())))))}}export{ExtractorResultSets,PurgeCSS,VariableNode,VariablesStructure,c as defaultOptions,p as mergeExtractorSelectors,d as setOptions,u 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"),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;
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("fs"),t=require("glob"),s=require("path"),r=require("postcss"),o=require("postcss-selector-parser"),i=require("util");function a(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function n(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 u=n(e),c=n(t),l=n(s),d=n(r),h=a(o);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:[]};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){const t=e.value.value.matchAll(/var\((.+?)[,)]/g);for(const e of t)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 g={access:i.promisify(u.access),readFile:i.promisify(u.readFile)};function v(e=[]){return Array.isArray(e)?{...m.safelist,standard:e}:{...m.safelist,...e}}async function S(e="purgecss.config.js"){let t;try{const s=l.resolve(process.cwd(),e);t=await function(e){return Promise.resolve().then((function(){return n(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:v(t.safelist)}}async function y(e,t){return new ExtractorResultSets(await t(e))}function b(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 w(...e){const t=new ExtractorResultSets([]);return e.forEach(t.merge,t),t}function x(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 A(e,t){return t.hasId(e.value)}function k(e,t){return t.hasTag(e.value)}function F(e){return"atrule"===(null==e?void 0:e.type)}function E(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=s.matchAll(/var\((.+?)[,)]/g);t.startsWith("--")?(this.variablesStructure.addVariable(e),this.variablesStructure.addVariableUsage(e,r)):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=x(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([]),r=[];for(const t of e)try{await g.access(t,u.constants.F_OK),r.push(t)}catch(e){r.push(...c.sync(t,{nodir:!0,ignore:this.options.skippedContentGlobs.map((e=>e.replace(/^\.\//,"")))}))}e.length>0&&0===r.length&&console.warn("No files found from the passed PurgeCSS option 'content'.");for(const e of r){const r=await g.readFile(e,"utf-8"),o=this.getFileExtractor(e,t),i=await y(r,o);s.merge(i)}return s}async extractSelectorsFromString(e,t){const s=new ExtractorResultSets([]);for(const{raw:r,extension:o}of e){const e=this.getFileExtractor(`.${o}`,t),i=await y(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:x(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)&&b(s,"next"))return void s.remove();if(e.parent&&F(e.parent)&&e.parent.name.endsWith("keyframes"))return;if(!E(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;const r=[];if(e.selector=h.default((e=>{e.walk((e=>{if("selector"!==e.type)return;this.shouldKeepSelector(e,t)||(this.options.rejected&&this.selectorsRemoved.add(e.toString()),this.options.rejectedCss&&r.push(e.toString()),e.remove())})),e.walk((e=>{"selector"===e.type&&e.toString()&&/(:where)|(:is)/.test(e.toString())&&e.walk((t=>{"pseudo"===t.type&&(":where"!==t.value&&":is"!==t.value||0===t.nodes.length&&e.remove())}))}))})).processSync(e.selector),e.selector&&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!!(E(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))}(o)&&(null==o||o.remove()),this.options.rejectedCss&&r.length>0){const t=e.clone(),s=null==o?void 0:o.clone().removeAll().append(t);t.selectors=r;const i=s||t;this.removedNodes.push(i)}}async getPurgedCSS(e,t){var s;const r=[],o=[];for(const t of e)"string"==typeof t?o.push(...c.sync(t,{nodir:!0,ignore:this.options.skippedContentGlobs})):o.push(t);for(const e of o){const o="string"==typeof e?this.options.stdin?e:await g.readFile(e,"utf-8"):e.raw,i="string"==typeof e&&!this.options.stdin,a=d.parse(o,{from:i?e:void 0});this.walkThroughCSS(a,t),this.options.fontFace&&this.removeUnusedFontFaces(),this.options.keyframes&&this.removeUnusedKeyframes(),this.options.variables&&this.removeUnusedCSSVariables();const n=a.toResult({map:this.options.sourceMap,to:"object"==typeof this.options.sourceMap?this.options.sourceMap.to:void 0}),u={css:n.toString(),file:"string"==typeof e?e:e.name};this.options.sourceMap&&(u.sourceMap=null===(s=n.map)||void 0===s?void 0:s.toString()),this.options.rejected&&(u.rejected=Array.from(this.selectorsRemoved),this.selectorsRemoved.clear()),this.options.rejectedCss&&(u.rejectedCss=d.root({nodes:this.removedNodes}).toString()),r.push(u)}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 S(e):{...m,...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)),a=t.filter((e=>"object"==typeof e)),n=await this.extractSelectorsFromFiles(i,r),u=await this.extractSelectorsFromString(a,r);return this.getPurgedCSS(s,w(n,u))}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)&&!function(e){return e.parent&&"pseudo"===e.parent.type&&(":where"===e.parent.value||":is"===e.parent.value)||!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&&(p.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=A(o,t);break;case"tag":s=k(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&&(b(e,"start")?(this.ignore=!0,e.remove()):b(e,"end")&&(this.ignore=!1,e.remove())))))}},exports.VariableNode=VariableNode,exports.VariablesStructure=VariablesStructure,exports.defaultOptions=m,exports.mergeExtractorSelectors=w,exports.setOptions=S,exports.standardizeSafelist=v;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "purgecss",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "Remove unused css selectors",
|
|
5
5
|
"author": "Ffloriel",
|
|
6
6
|
"homepage": "https://purgecss.com",
|
|
@@ -40,13 +40,13 @@
|
|
|
40
40
|
"test": "jest"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"commander": "^
|
|
44
|
-
"glob": "^
|
|
43
|
+
"commander": "^12.0.0",
|
|
44
|
+
"glob": "^10.3.10",
|
|
45
45
|
"postcss": "^8.4.4",
|
|
46
46
|
"postcss-selector-parser": "^6.0.7"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@types/glob": "^
|
|
49
|
+
"@types/glob": "^8.0.0"
|
|
50
50
|
},
|
|
51
51
|
"bugs": {
|
|
52
52
|
"url": "https://github.com/FullHuman/purgecss/issues"
|