purgecss 4.0.2 → 4.1.2

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 CHANGED
@@ -1,11 +1,10 @@
1
1
  # PurgeCSS
2
2
 
3
- ![David](https://img.shields.io/david/FullHuman/purgecss?path=packages%2Fpurgecss&style=for-the-badge)
4
- ![David](https://img.shields.io/david/dev/FullHuman/purgecss?path=packages%2Fpurgecss&style=for-the-badge)
5
- ![Dependabot](https://img.shields.io/badge/dependabot-enabled-%23024ea4?style=for-the-badge)
6
- ![npm](https://img.shields.io/npm/v/purgecss?style=for-the-badge)
7
- ![npm](https://img.shields.io/npm/dw/purgecss?style=for-the-badge)
3
+ [![npm](https://img.shields.io/npm/v/purgecss?style=for-the-badge)](https://www.npmjs.com/package/purgecss)
4
+ ![npm](https://img.shields.io/npm/dm/purgecss?style=for-the-badge)
8
5
  ![GitHub](https://img.shields.io/github/license/FullHuman/purgecss?style=for-the-badge)
6
+ ![Dependabot](https://img.shields.io/badge/dependabot-enabled-%23024ea4?style=for-the-badge)
7
+ [![Coverage Status](https://img.shields.io/coveralls/github/FullHuman/purgecss/main?style=for-the-badge)](https://coveralls.io/github/FullHuman/purgecss?branch=main)
9
8
 
10
9
  <p align="center">
11
10
  <img src="https://i.imgur.com/UEiUiJ0.png" height="200" width="200" alt="PurgeCSS logo"/>
@@ -19,7 +18,8 @@ This is where PurgeCSS comes into play. PurgeCSS analyzes your content and your
19
18
 
20
19
  ## Sponsors 🥰
21
20
 
22
- [<img src="https://avatars0.githubusercontent.com/u/67109815?v=4" height="85">](https://tailwindcss.com)
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/6852555?&v=4" height="85">](https://vertistudio.com/)
23
23
 
24
24
  ## Documentation
25
25
 
@@ -0,0 +1 @@
1
+ export {};
package/bin/purgecss.js CHANGED
@@ -1,88 +1,2 @@
1
1
  #!/usr/bin/env node
2
- const program = require("commander");
3
- const fs = require("fs");
4
- const {
5
- default: PurgeCSS,
6
- defaultOptions,
7
- setOptions,
8
- standardizeSafelist,
9
- } = require("../lib/purgecss");
10
-
11
- async function writeCSSToFile(filePath, css) {
12
- try {
13
- await fs.promises.writeFile(filePath, css);
14
- } catch (err) {
15
- console.error(err.message);
16
- }
17
- }
18
-
19
- program
20
- .usage("--css <css...> --content <content...> [options]")
21
- .option("-con, --content <files...>", "glob of content files")
22
- .option("-css, --css <files...>", "glob of css files")
23
- .option("-c, --config <path>", "path to the configuration file")
24
- .option(
25
- "-o, --output <path>",
26
- "file path directory to write purged css files to"
27
- )
28
- .option("-font, --font-face", "option to remove unused font-faces")
29
- .option("-keyframes, --keyframes", "option to remove unused keyframes")
30
- .option("-rejected, --rejected", "option to output rejected selectors")
31
- .option(
32
- "-s, --safelist <list...>",
33
- "list of classes that should not be removed"
34
- )
35
- .option(
36
- "-b, --blocklist <list...>",
37
- "list of selectors that should be removed"
38
- );
39
-
40
- program.parse(process.argv);
41
-
42
- const run = async () => {
43
- // config file is not specified or the content and css are not,
44
- // PurgeCSS will not run
45
- if (!program.config && !(program.content && program.css)) {
46
- program.help();
47
- }
48
-
49
- // if the config file is present, use it
50
- // other options specified will override
51
- let options = defaultOptions;
52
- if (program.config) {
53
- options = await setOptions(program.config);
54
- }
55
- if (program.content) options.content = program.content;
56
- if (program.css) options.css = program.css;
57
- if (program.fontFace) options.fontFace = program.fontFace;
58
- if (program.keyframes) options.keyframes = program.keyframes;
59
- if (program.rejected) options.rejected = program.rejected;
60
- if (program.variables) options.variables = program.variables;
61
- if (program.safelist)
62
- options.safelist = standardizeSafelist(program.safelist);
63
- if (program.blocklist) options.blocklist = program.blocklist;
64
-
65
- const purged = await new PurgeCSS().purge(options);
66
- const output = options.output || program.output;
67
- // output results in specified directory
68
- if (output) {
69
- if (purged.length === 1 && output.endsWith(".css")) {
70
- await writeCSSToFile(output, purged[0].css);
71
- return;
72
- }
73
-
74
- for (const purgedResult of purged) {
75
- const fileName = purgedResult.file.split("/").pop();
76
- await writeCSSToFile(`${output}/${fileName}`, purgedResult.css);
77
- }
78
- } else {
79
- console.log(JSON.stringify(purged));
80
- }
81
- };
82
-
83
- try {
84
- run();
85
- } catch (error) {
86
- console.error(error.message);
87
- process.exit(1);
88
- }
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)}
package/lib/purgecss.d.ts CHANGED
@@ -1,10 +1,19 @@
1
1
  import * as postcss from "postcss";
2
+ type PostCSSRoot = postcss.Root;
3
+ interface AtRules {
4
+ fontFace: Array<{
5
+ name: string;
6
+ node: postcss.AtRule;
7
+ }>;
8
+ keyframes: postcss.AtRule[];
9
+ }
2
10
  interface RawContent<T = string> {
3
11
  extension: string;
4
12
  raw: T;
5
13
  }
6
14
  interface RawCSS {
7
15
  raw: string;
16
+ name?: string;
8
17
  }
9
18
  interface ExtractorResultDetailed {
10
19
  attributes: {
@@ -22,6 +31,7 @@ interface Extractors {
22
31
  extensions: string[];
23
32
  extractor: ExtractorFunction;
24
33
  }
34
+ type IgnoreType = "end" | "start" | "next";
25
35
  type StringRegExpArray = Array<RegExp | string>;
26
36
  type ComplexSafelist = {
27
37
  standard?: StringRegExpArray;
@@ -40,11 +50,14 @@ interface UserDefinedOptions {
40
50
  keyframes?: boolean;
41
51
  output?: string;
42
52
  rejected?: boolean;
53
+ rejectedCss?: boolean;
43
54
  stdin?: boolean;
44
55
  stdout?: boolean;
45
56
  variables?: boolean;
46
57
  safelist?: UserDefinedSafelist;
47
58
  blocklist?: StringRegExpArray;
59
+ skippedContentGlobs?: Array<string>;
60
+ dynamicAttributes?: string[];
48
61
  }
49
62
  interface Options {
50
63
  content: Array<string | RawContent>;
@@ -55,18 +68,21 @@ interface Options {
55
68
  keyframes: boolean;
56
69
  output?: string;
57
70
  rejected: boolean;
71
+ rejectedCss: boolean;
58
72
  stdin: boolean;
59
73
  stdout: boolean;
60
74
  variables: boolean;
61
75
  safelist: Required<ComplexSafelist>;
62
76
  blocklist: StringRegExpArray;
77
+ skippedContentGlobs: Array<string>;
78
+ dynamicAttributes: string[];
63
79
  }
64
80
  interface ResultPurge {
65
81
  css: string;
82
+ rejectedCss?: string;
66
83
  file?: string;
67
84
  rejected?: string[];
68
85
  }
69
- declare const defaultOptions: Options;
70
86
  declare class ExtractorResultSets {
71
87
  private undetermined;
72
88
  private attrNames;
@@ -86,6 +102,7 @@ declare class ExtractorResultSets {
86
102
  hasId(id: string): boolean;
87
103
  hasTag(tag: string): boolean;
88
104
  }
105
+ declare const defaultOptions: Options;
89
106
  declare function standardizeSafelist(userDefinedSafelist?: UserDefinedSafelist): Required<ComplexSafelist>;
90
107
  /**
91
108
  * Load the configuration file from the path
@@ -104,6 +121,7 @@ declare class PurgeCSS {
104
121
  private usedAnimations;
105
122
  private usedFontFaces;
106
123
  selectorsRemoved: Set<string>;
124
+ removedNodes: postcss.Node[];
107
125
  private variablesStructure;
108
126
  options: Options;
109
127
  private collectDeclarationsData;
@@ -274,6 +292,6 @@ declare class PurgeCSS {
274
292
  * @param root root node of the postcss AST
275
293
  * @param selectors selectors used in content files
276
294
  */
277
- walkThroughCSS(root: postcss.Root, selectors: ExtractorResultSets): void;
295
+ walkThroughCSS(root: PostCSSRoot, selectors: ExtractorResultSets): void;
278
296
  }
279
- export { PurgeCSS as default, PurgeCSS, defaultOptions, standardizeSafelist, setOptions, mergeExtractorSelectors };
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 };
@@ -1,10 +1,19 @@
1
1
  import * as postcss from "postcss";
2
+ type PostCSSRoot = postcss.Root;
3
+ interface AtRules {
4
+ fontFace: Array<{
5
+ name: string;
6
+ node: postcss.AtRule;
7
+ }>;
8
+ keyframes: postcss.AtRule[];
9
+ }
2
10
  interface RawContent<T = string> {
3
11
  extension: string;
4
12
  raw: T;
5
13
  }
6
14
  interface RawCSS {
7
15
  raw: string;
16
+ name?: string;
8
17
  }
9
18
  interface ExtractorResultDetailed {
10
19
  attributes: {
@@ -22,6 +31,7 @@ interface Extractors {
22
31
  extensions: string[];
23
32
  extractor: ExtractorFunction;
24
33
  }
34
+ type IgnoreType = "end" | "start" | "next";
25
35
  type StringRegExpArray = Array<RegExp | string>;
26
36
  type ComplexSafelist = {
27
37
  standard?: StringRegExpArray;
@@ -40,11 +50,14 @@ interface UserDefinedOptions {
40
50
  keyframes?: boolean;
41
51
  output?: string;
42
52
  rejected?: boolean;
53
+ rejectedCss?: boolean;
43
54
  stdin?: boolean;
44
55
  stdout?: boolean;
45
56
  variables?: boolean;
46
57
  safelist?: UserDefinedSafelist;
47
58
  blocklist?: StringRegExpArray;
59
+ skippedContentGlobs?: Array<string>;
60
+ dynamicAttributes?: string[];
48
61
  }
49
62
  interface Options {
50
63
  content: Array<string | RawContent>;
@@ -55,18 +68,21 @@ interface Options {
55
68
  keyframes: boolean;
56
69
  output?: string;
57
70
  rejected: boolean;
71
+ rejectedCss: boolean;
58
72
  stdin: boolean;
59
73
  stdout: boolean;
60
74
  variables: boolean;
61
75
  safelist: Required<ComplexSafelist>;
62
76
  blocklist: StringRegExpArray;
77
+ skippedContentGlobs: Array<string>;
78
+ dynamicAttributes: string[];
63
79
  }
64
80
  interface ResultPurge {
65
81
  css: string;
82
+ rejectedCss?: string;
66
83
  file?: string;
67
84
  rejected?: string[];
68
85
  }
69
- declare const defaultOptions: Options;
70
86
  declare class ExtractorResultSets {
71
87
  private undetermined;
72
88
  private attrNames;
@@ -86,6 +102,7 @@ declare class ExtractorResultSets {
86
102
  hasId(id: string): boolean;
87
103
  hasTag(tag: string): boolean;
88
104
  }
105
+ declare const defaultOptions: Options;
89
106
  declare function standardizeSafelist(userDefinedSafelist?: UserDefinedSafelist): Required<ComplexSafelist>;
90
107
  /**
91
108
  * Load the configuration file from the path
@@ -104,6 +121,7 @@ declare class PurgeCSS {
104
121
  private usedAnimations;
105
122
  private usedFontFaces;
106
123
  selectorsRemoved: Set<string>;
124
+ removedNodes: postcss.Node[];
107
125
  private variablesStructure;
108
126
  options: Options;
109
127
  private collectDeclarationsData;
@@ -274,6 +292,6 @@ declare class PurgeCSS {
274
292
  * @param root root node of the postcss AST
275
293
  * @param selectors selectors used in content files
276
294
  */
277
- walkThroughCSS(root: postcss.Root, selectors: ExtractorResultSets): void;
295
+ walkThroughCSS(root: PostCSSRoot, selectors: ExtractorResultSets): void;
278
296
  }
279
- export { PurgeCSS as default, PurgeCSS, defaultOptions, standardizeSafelist, setOptions, mergeExtractorSelectors };
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 };
@@ -1 +1 @@
1
- import{parse as e}from"postcss";import t from"postcss-selector-parser";import{access as s,readFile as r,constants as i}from"fs";import{promisify as a}from"util";import n from"glob";import o from"path";const c={css:[],content:[],defaultExtractor:e=>e.match(/[A-Za-z0-9_-]+/g)||[],extractors:[],fontFace:!1,keyframes:!1,rejected:!1,stdin:!1,stdout:!1,variables:!1,safelist:{standard:[],deep:[],greedy:[],variables:[],keyframes:[]},blocklist:[]},l=["*","::-webkit-scrollbar","::selection",":root","::before","::after"];class u{constructor(e){this.nodes=[],this.isUsed=!1,this.value=e}}class h{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 u(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.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)];for(;0!==t.length;){const e=t.pop();e&&!e.isUsed&&(e.isUsed=!0,t.push(...e.nodes))}}removeUnused(){for(const e of this.usedVariables)this.setAsUsed(e);for(const[e,t]of this.nodes)t.isUsed||this.isVariablesSafelisted(e)||t.value.remove()}isVariablesSafelisted(e){return this.safelist.some((t=>"string"==typeof t?t===e:t.test(e)))}}function d(e,t){t&&t.forEach(e.add,e)}class f{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)?d(this.undetermined,e):e instanceof f?(d(this.undetermined,e.undetermined),d(this.attrNames,e.attrNames),d(this.attrValues,e.attrValues),d(this.classes,e.classes),d(this.ids,e.ids),d(this.tags,e.tags)):(d(this.undetermined,e.undetermined),e.attributes&&(d(this.attrNames,e.attributes.names),d(this.attrValues,e.attributes.values)),d(this.classes,e.classes),d(this.ids,e.ids),d(this.tags,e.tags)),this}hasAttrName(e){return this.attrNames.has(e)||this.undetermined.has(e)}someAttrValue(e){for(const t of this.attrValues)if(e(t))return!0;for(const t of this.undetermined)if(e(t))return!0;return!1}hasAttrPrefix(e){return this.someAttrValue((t=>t.startsWith(e)))}hasAttrSuffix(e){return this.someAttrValue((t=>t.endsWith(e)))}hasAttrSubstr(e){return e.trim().split(" ").every((e=>this.someAttrValue((t=>t.includes(e)))))}hasAttrValue(e){return this.attrValues.has(e)||this.undetermined.has(e)}hasClass(e){return this.classes.has(e)||this.undetermined.has(e)}hasId(e){return this.ids.has(e)||this.undetermined.has(e)}hasTag(e){return this.tags.has(e)||this.undetermined.has(e)}}const m={access:a(s),readFile:a(r)};function p(e=[]){return Array.isArray(e)?{...c.safelist,standard:e}:{...c.safelist,...e}}async function g(e="purgecss.config.js"){let t;try{const s=o.join(process.cwd(),e);t=await import(s)}catch(e){throw new Error("Error loading the config file "+e.message)}return{...c,...t,safelist:p(t.safelist)}}async function v(e,t){return new f(await t(e))}function y(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 S(...e){const t=new f([]);return e.forEach(t.merge,t),t}function b(e){return e.replace(/(^["'])|(["']$)/g,"")}function w(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 A(e,t){return t.hasTag(e.value)}function V(e){return"atrule"===(null==e?void 0:e.type)}function x(e){return"rule"===(null==e?void 0:e.type)}class k{constructor(){this.ignore=!1,this.atRules={fontFace:[],keyframes:[]},this.usedAnimations=new Set,this.usedFontFaces=new Set,this.selectorsRemoved=new Set,this.variablesStructure=new h,this.options=c}collectDeclarationsData(e){const{prop:t,value:s}=e;if(this.options.variables){const r=function(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}(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=b(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 f([]);for(const r of e){let e=[];try{await m.access(r,i.F_OK),e.push(r)}catch(t){e=n.sync(r,{nodir:!0})}for(const r of e){const e=await m.readFile(r,"utf-8"),i=this.getFileExtractor(r,t),a=await v(e,i);s.merge(a)}}return s}async extractSelectorsFromString(e,t){const s=new f([]);for(const{raw:r,extension:i}of e){const e=this.getFileExtractor("."+i,t),a=await v(r,e);s.merge(a)}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:b(t.value),node:e})}async evaluateRule(e,s){if(this.ignore)return;const r=e.prev();if(function(e){return"comment"===(null==e?void 0:e.type)}(r)&&y(r,"next"))return void r.remove();if(e.parent&&V(e.parent)&&"keyframes"===e.parent.name)return;if(!x(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 i=!0;if(e.selector=t((e=>{e.walk((e=>{"selector"===e.type&&(i=this.shouldKeepSelector(e,s),i||(this.options.rejected&&this.selectorsRemoved.add(e.toString()),e.remove()))}))})).processSync(e.selector),i&&void 0!==e.nodes)for(const t of e.nodes)"decl"===t.type&&this.collectDeclarationsData(t);const a=e.parent;e.selector||e.remove(),function(e){return!!(x(e)&&!e.selector||(null==e?void 0:e.nodes)&&!e.nodes.length||V(e)&&(!e.nodes&&!e.params||!e.params&&e.nodes&&!e.nodes.length))}(a)&&(null==a||a.remove())}async getPurgedCSS(t,s){const r=[],i=[];for(const e of t)"string"==typeof e?i.push(...n.sync(e,{nodir:!0})):i.push(e);for(const t of i){const i="string"==typeof t?this.options.stdin?t:await m.readFile(t,"utf-8"):t.raw,a=e(i);this.walkThroughCSS(a,s),this.options.fontFace&&this.removeUnusedFontFaces(),this.options.keyframes&&this.removeUnusedKeyframes(),this.options.variables&&this.removeUnusedCSSVariables();const n={css:a.toString(),file:"string"==typeof t?t:void 0};"string"==typeof t&&(n.file=t),this.options.rejected&&(n.rejected=Array.from(this.selectorsRemoved),this.selectorsRemoved.clear()),r.push(n)}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)));return l.includes(e)||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 g(e):{...c,...e,safelist:p(e.safelist)};const{content:t,css:s,extractors:r,safelist:i}=this.options;this.options.variables&&(this.variablesStructure.safelist=i.variables||[]);const a=t.filter((e=>"string"==typeof e)),n=t.filter((e=>"object"==typeof e)),o=await this.extractSelectorsFromFiles(a,r),l=await this.extractSelectorsFromString(n,r);return this.getPurgedCSS(s,S(o,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 i of e.nodes){const e=this.getSelectorValue(i);if(e&&this.isSelectorSafelistedDeep(e))return!0;if(e&&(l.includes(e)||this.isSelectorSafelisted(e)))s=!0;else{if(e&&this.isSelectorBlocklisted(e))return!1;switch(i.type){case"attribute":s=!!["value","checked","selected","open"].includes(i.attribute)||w(i,t);break;case"class":r=i,s=t.hasClass(r.value);break;case"id":s=F(i,t);break;case"tag":s=A(i,t);break;default:continue}if(!s)return!1}}var r;return s}walkThroughCSS(e,t){e.walk((e=>"rule"===e.type?this.evaluateRule(e,t):"atrule"===e.type?this.evaluateAtRule(e):void("comment"===e.type&&(y(e,"start")?(this.ignore=!0,e.remove()):y(e,"end")&&(this.ignore=!1,e.remove())))))}}export default k;export{k as PurgeCSS,c as defaultOptions,S as mergeExtractorSelectors,g as setOptions,p as standardizeSafelist};
1
+ import*as e from"fs";import t from"glob";import s from"path";import*as r from"postcss";import i from"postcss-selector-parser";import{promisify as o}from"util";function n(e,t){t&&t.forEach(e.add,e)}class a{constructor(e){this.undetermined=new Set,this.attrNames=new Set,this.attrValues=new Set,this.classes=new Set,this.ids=new Set,this.tags=new Set,this.merge(e)}merge(e){return Array.isArray(e)?n(this.undetermined,e):e instanceof a?(n(this.undetermined,e.undetermined),n(this.attrNames,e.attrNames),n(this.attrValues,e.attrValues),n(this.classes,e.classes),n(this.ids,e.ids),n(this.tags,e.tags)):(n(this.undetermined,e.undetermined),e.attributes&&(n(this.attrNames,e.attributes.names),n(this.attrValues,e.attributes.values)),n(this.classes,e.classes),n(this.ids,e.ids),n(this.tags,e.tags)),this}hasAttrName(e){return this.attrNames.has(e)||this.undetermined.has(e)}someAttrValue(e){for(const t of this.attrValues)if(e(t))return!0;for(const t of this.undetermined)if(e(t))return!0;return!1}hasAttrPrefix(e){return this.someAttrValue((t=>t.startsWith(e)))}hasAttrSuffix(e){return this.someAttrValue((t=>t.endsWith(e)))}hasAttrSubstr(e){return e.trim().split(" ").every((e=>this.someAttrValue((t=>t.includes(e)))))}hasAttrValue(e){return this.attrValues.has(e)||this.undetermined.has(e)}hasClass(e){return this.classes.has(e)||this.undetermined.has(e)}hasId(e){return this.ids.has(e)||this.undetermined.has(e)}hasTag(e){return this.tags.has(e)||this.undetermined.has(e)}}const c=["*",":root",":after",":before"],l={css:[],content:[],defaultExtractor:e=>e.match(/[A-Za-z0-9_-]+/g)||[],extractors:[],fontFace:!1,keyframes:!1,rejected:!1,rejectedCss:!1,stdin:!1,stdout:!1,variables:!1,safelist:{standard:[],deep:[],greedy:[],variables:[],keyframes:[]},blocklist:[],skippedContentGlobs:[],dynamicAttributes:[]};function u(e,t){const s=[];return e.replace(t,(function(){const t=arguments,r=Array.prototype.slice.call(t,0,-2);return r.input=t[t.length-1],r.index=t[t.length-2],s.push(r),e})),s}class h{constructor(e){this.nodes=[],this.isUsed=!1,this.value=e}}class d{constructor(){this.nodes=new Map,this.usedVariables=new Set,this.safelist=[]}addVariable(e){const{prop:t}=e;if(this.nodes.has(t)){const s=new h(e),r=this.nodes.get(t)||[];this.nodes.set(t,[...r,s])}else{const s=new h(e);this.nodes.set(t,[s])}}addVariableUsage(e,t){const{prop:s}=e,r=this.nodes.get(s);for(const e of t){const t=e[1];if(this.nodes.has(t)){const e=this.nodes.get(t);null==r||r.forEach((t=>{null==e||e.forEach((e=>t.nodes.push(e)))}))}}}addVariableUsageInProperties(e){for(const t of e){const e=t[1];this.usedVariables.add(e)}}setAsUsed(e){const t=this.nodes.get(e);if(t){const e=[...t];for(;0!==e.length;){const t=e.pop();t&&!t.isUsed&&(t.isUsed=!0,e.push(...t.nodes))}}}removeUnused(){for(const e of this.usedVariables){const t=this.nodes.get(e);if(t)for(const e of t){u(e.value.value,/var\((.+?)[,)]/g).forEach((e=>{this.usedVariables.has(e[1])||this.usedVariables.add(e[1])}))}}for(const e of this.usedVariables)this.setAsUsed(e);for(const[e,t]of this.nodes)for(const s of t)s.isUsed||this.isVariablesSafelisted(e)||s.value.remove()}isVariablesSafelisted(e){return this.safelist.some((t=>"string"==typeof t?t===e:t.test(e)))}}const f={access:o(e.access),readFile:o(e.readFile)};function p(e=[]){return Array.isArray(e)?{...l.safelist,standard:e}:{...l.safelist,...e}}async function m(e="purgecss.config.js"){let t;try{const r=s.resolve(process.cwd(),e);t=await import(r)}catch(e){throw new Error(`Error loading the config file ${e.message}`)}return{...l,...t,safelist:p(t.safelist)}}async function g(e,t){return new a(await t(e))}function v(e,t){switch(t){case"next":return e.text.includes("purgecss ignore");case"start":return e.text.includes("purgecss start ignore");case"end":return e.text.includes("purgecss end ignore")}}function y(...e){const t=new a([]);return e.forEach(t.merge,t),t}function S(e){return e.replace(/(^["'])|(["']$)/g,"")}function b(e,t){if(!t.hasAttrName(e.attribute))return!1;if(void 0===e.value)return!0;switch(e.operator){case"$=":return t.hasAttrSuffix(e.value);case"~=":case"*=":return t.hasAttrSubstr(e.value);case"=":return t.hasAttrValue(e.value);case"|=":case"^=":return t.hasAttrPrefix(e.value);default:return!0}}function w(e,t){return t.hasId(e.value)}function A(e,t){return t.hasTag(e.value)}function F(e){return"atrule"===(null==e?void 0:e.type)}function V(e){return"rule"===(null==e?void 0:e.type)}class k{constructor(){this.ignore=!1,this.atRules={fontFace:[],keyframes:[]},this.usedAnimations=new Set,this.usedFontFaces=new Set,this.selectorsRemoved=new Set,this.removedNodes=[],this.variablesStructure=new d,this.options=l}collectDeclarationsData(e){const{prop:t,value:s}=e;if(this.options.variables){const r=u(s,/var\((.+?)[,)]/g);t.startsWith("--")?(this.variablesStructure.addVariable(e),r.length>0&&this.variablesStructure.addVariableUsage(e,r)):r.length>0&&this.variablesStructure.addVariableUsageInProperties(r)}if(!this.options.keyframes||"animation"!==t&&"animation-name"!==t)if(this.options.fontFace){if("font-family"===t)for(const e of s.split(",")){const t=S(e.trim());this.usedFontFaces.add(t)}}else;else for(const e of s.split(/[\s,]+/))this.usedAnimations.add(e)}getFileExtractor(e,t){const s=t.find((t=>t.extensions.find((t=>e.endsWith(t)))));return void 0===s?this.options.defaultExtractor:s.extractor}async extractSelectorsFromFiles(s,r){const i=new a([]);for(const o of s){let s=[];try{await f.access(o,e.constants.F_OK),s.push(o)}catch(e){s=t.sync(o,{nodir:!0,ignore:this.options.skippedContentGlobs})}for(const e of s){const t=await f.readFile(e,"utf-8"),s=this.getFileExtractor(e,r),o=await g(t,s);i.merge(o)}}return i}async extractSelectorsFromString(e,t){const s=new a([]);for(const{raw:r,extension:i}of e){const e=this.getFileExtractor(`.${i}`,t),o=await g(r,e);s.merge(o)}return s}evaluateAtRule(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name&&e.nodes)for(const t of e.nodes)"decl"===t.type&&"font-family"===t.prop&&this.atRules.fontFace.push({name:S(t.value),node:e})}evaluateRule(e,t){if(this.ignore)return;const s=e.prev();if(function(e){return"comment"===(null==e?void 0:e.type)}(s)&&v(s,"next"))return void s.remove();if(e.parent&&F(e.parent)&&e.parent.name.endsWith("keyframes"))return;if(!V(e))return;if(function(e){let t=!1;return e.walkComments((e=>{e&&"comment"===e.type&&e.text.includes("purgecss ignore current")&&(t=!0,e.remove())})),t}(e))return;let r=!0;const o=[];if(e.selector=i((e=>{e.walk((e=>{"selector"===e.type&&(r=this.shouldKeepSelector(e,t),r||(this.options.rejected&&this.selectorsRemoved.add(e.toString()),this.options.rejectedCss&&o.push(e.toString()),e.remove()))}))})).processSync(e.selector),r&&void 0!==e.nodes)for(const t of e.nodes)"decl"===t.type&&this.collectDeclarationsData(t);const n=e.parent;if(e.selector||e.remove(),function(e){return!!(V(e)&&!e.selector||(null==e?void 0:e.nodes)&&!e.nodes.length||F(e)&&(!e.nodes&&!e.params||!e.params&&e.nodes&&!e.nodes.length))}(n)&&(null==n||n.remove()),this.options.rejectedCss&&o.length>0){const t=e.clone(),s=null==n?void 0:n.clone().removeAll().append(t);t.selectors=o;const r=s||t;this.removedNodes.push(r)}}async getPurgedCSS(e,s){const i=[],o=[];for(const s of e)"string"==typeof s?o.push(...t.sync(s,{nodir:!0,ignore:this.options.skippedContentGlobs})):o.push(s);for(const e of o){const t="string"==typeof e?this.options.stdin?e:await f.readFile(e,"utf-8"):e.raw,o=r.parse(t);this.walkThroughCSS(o,s),this.options.fontFace&&this.removeUnusedFontFaces(),this.options.keyframes&&this.removeUnusedKeyframes(),this.options.variables&&this.removeUnusedCSSVariables();const n={css:o.toString(),file:"string"==typeof e?e:e.name};this.options.rejected&&(n.rejected=Array.from(this.selectorsRemoved),this.selectorsRemoved.clear()),this.options.rejectedCss&&(n.rejectedCss=r.root({nodes:this.removedNodes}).toString()),i.push(n)}return i}isKeyframesSafelisted(e){return this.options.safelist.keyframes.some((t=>"string"==typeof t?t===e:t.test(e)))}isSelectorBlocklisted(e){return this.options.blocklist.some((t=>"string"==typeof t?t===e:t.test(e)))}isSelectorSafelisted(e){const t=this.options.safelist.standard.some((t=>"string"==typeof t?t===e:t.test(e))),s=/^::.*/.test(e);return c.includes(e)||s||t}isSelectorSafelistedDeep(e){return this.options.safelist.deep.some((t=>t.test(e)))}isSelectorSafelistedGreedy(e){return this.options.safelist.greedy.some((t=>t.test(e)))}async purge(e){this.options="object"!=typeof e?await m(e):{...l,...e,safelist:p(e.safelist)};const{content:t,css:s,extractors:r,safelist:i}=this.options;this.options.variables&&(this.variablesStructure.safelist=i.variables||[]);const o=t.filter((e=>"string"==typeof e)),n=t.filter((e=>"object"==typeof e)),a=await this.extractSelectorsFromFiles(o,r),c=await this.extractSelectorsFromString(n,r);return this.getPurgedCSS(s,y(a,c))}removeUnusedCSSVariables(){this.variablesStructure.removeUnused()}removeUnusedFontFaces(){for(const{name:e,node:t}of this.atRules.fontFace)this.usedFontFaces.has(e)||t.remove()}removeUnusedKeyframes(){for(const e of this.atRules.keyframes)this.usedAnimations.has(e.params)||this.isKeyframesSafelisted(e.params)||e.remove()}getSelectorValue(e){return"attribute"===e.type&&e.attribute||e.value}shouldKeepSelector(e,t){if(function(e){return e.parent&&"pseudo"===e.parent.type&&e.parent.value.startsWith(":")||!1}(e))return!0;if(this.options.safelist.greedy.length>0){if(e.nodes.map(this.getSelectorValue).some((e=>e&&this.isSelectorSafelistedGreedy(e))))return!0}let s=!1;for(const i of e.nodes){const e=this.getSelectorValue(i);if(e&&this.isSelectorSafelistedDeep(e))return!0;if(e&&(c.includes(e)||this.isSelectorSafelisted(e)))s=!0;else{if(e&&this.isSelectorBlocklisted(e))return!1;switch(i.type){case"attribute":s=!![...this.options.dynamicAttributes,"value","checked","selected","open"].includes(i.attribute)||b(i,t);break;case"class":r=i,s=t.hasClass(r.value);break;case"id":s=w(i,t);break;case"tag":s=A(i,t);break;default:continue}if(!s)return!1}}var r;return s}walkThroughCSS(e,t){e.walk((e=>"rule"===e.type?this.evaluateRule(e,t):"atrule"===e.type?this.evaluateAtRule(e):void("comment"===e.type&&(v(e,"start")?(this.ignore=!0,e.remove()):v(e,"end")&&(this.ignore=!1,e.remove())))))}}export{k as PurgeCSS,k as default,l as defaultOptions,y as mergeExtractorSelectors,m as setOptions,p as standardizeSafelist};
package/lib/purgecss.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("postcss"),t=require("postcss-selector-parser"),s=require("fs"),r=require("util"),i=require("glob"),a=require("path");function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function o(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(t),c=n(i),l=n(a);const d={css:[],content:[],defaultExtractor:e=>e.match(/[A-Za-z0-9_-]+/g)||[],extractors:[],fontFace:!1,keyframes:!1,rejected:!1,stdin:!1,stdout:!1,variables:!1,safelist:{standard:[],deep:[],greedy:[],variables:[],keyframes:[]},blocklist:[]},f=["*","::-webkit-scrollbar","::selection",":root","::before","::after"];class h{constructor(e){this.nodes=[],this.isUsed=!1,this.value=e}}class p{constructor(){this.nodes=new Map,this.usedVariables=new Set,this.safelist=[]}addVariable(e){const{prop:t}=e;if(!this.nodes.has(t)){const s=new h(e);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.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)];for(;0!==t.length;){const e=t.pop();e&&!e.isUsed&&(e.isUsed=!0,t.push(...e.nodes))}}removeUnused(){for(const e of this.usedVariables)this.setAsUsed(e);for(const[e,t]of this.nodes)t.isUsed||this.isVariablesSafelisted(e)||t.value.remove()}isVariablesSafelisted(e){return this.safelist.some((t=>"string"==typeof t?t===e:t.test(e)))}}function m(e,t){t&&t.forEach(e.add,e)}class g{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)?m(this.undetermined,e):e instanceof g?(m(this.undetermined,e.undetermined),m(this.attrNames,e.attrNames),m(this.attrValues,e.attrValues),m(this.classes,e.classes),m(this.ids,e.ids),m(this.tags,e.tags)):(m(this.undetermined,e.undetermined),e.attributes&&(m(this.attrNames,e.attributes.names),m(this.attrValues,e.attributes.values)),m(this.classes,e.classes),m(this.ids,e.ids),m(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 v={access:r.promisify(s.access),readFile:r.promisify(s.readFile)};function y(e=[]){return Array.isArray(e)?{...d.safelist,standard:e}:{...d.safelist,...e}}async function S(e="purgecss.config.js"){let t;try{const s=l.default.join(process.cwd(),e);t=await Promise.resolve().then((function(){return o(require(s))}))}catch(e){throw new Error("Error loading the config file "+e.message)}return{...d,...t,safelist:y(t.safelist)}}async function b(e,t){return new g(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 g([]);return e.forEach(t.merge,t),t}function F(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 V(e,t){return t.hasId(e.value)}function k(e,t){return t.hasTag(e.value)}function U(e){return"atrule"===(null==e?void 0:e.type)}function j(e){return"rule"===(null==e?void 0:e.type)}class R{constructor(){this.ignore=!1,this.atRules={fontFace:[],keyframes:[]},this.usedAnimations=new Set,this.usedFontFaces=new Set,this.selectorsRemoved=new Set,this.variablesStructure=new p,this.options=d}collectDeclarationsData(e){const{prop:t,value:s}=e;if(this.options.variables){const r=function(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}(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=F(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 r=new g([]);for(const i of e){let e=[];try{await v.access(i,s.constants.F_OK),e.push(i)}catch(t){e=c.default.sync(i,{nodir:!0})}for(const s of e){const e=await v.readFile(s,"utf-8"),i=this.getFileExtractor(s,t),a=await b(e,i);r.merge(a)}}return r}async extractSelectorsFromString(e,t){const s=new g([]);for(const{raw:r,extension:i}of e){const e=this.getFileExtractor("."+i,t),a=await b(r,e);s.merge(a)}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:F(t.value),node:e})}async 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&&U(e.parent)&&"keyframes"===e.parent.name)return;if(!j(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;if(e.selector=u.default((e=>{e.walk((e=>{"selector"===e.type&&(r=this.shouldKeepSelector(e,t),r||(this.options.rejected&&this.selectorsRemoved.add(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;e.selector||e.remove(),function(e){return!!(j(e)&&!e.selector||(null==e?void 0:e.nodes)&&!e.nodes.length||U(e)&&(!e.nodes&&!e.params||!e.params&&e.nodes&&!e.nodes.length))}(i)&&(null==i||i.remove())}async getPurgedCSS(t,s){const r=[],i=[];for(const e of t)"string"==typeof e?i.push(...c.default.sync(e,{nodir:!0})):i.push(e);for(const t of i){const i="string"==typeof t?this.options.stdin?t:await v.readFile(t,"utf-8"):t.raw,a=e.parse(i);this.walkThroughCSS(a,s),this.options.fontFace&&this.removeUnusedFontFaces(),this.options.keyframes&&this.removeUnusedKeyframes(),this.options.variables&&this.removeUnusedCSSVariables();const n={css:a.toString(),file:"string"==typeof t?t:void 0};"string"==typeof t&&(n.file=t),this.options.rejected&&(n.rejected=Array.from(this.selectorsRemoved),this.selectorsRemoved.clear()),r.push(n)}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)));return f.includes(e)||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):{...d,...e,safelist:y(e.safelist)};const{content:t,css:s,extractors:r,safelist:i}=this.options;this.options.variables&&(this.variablesStructure.safelist=i.variables||[]);const a=t.filter((e=>"string"==typeof e)),n=t.filter((e=>"object"==typeof e)),o=await this.extractSelectorsFromFiles(a,r),u=await this.extractSelectorsFromString(n,r);return this.getPurgedCSS(s,x(o,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))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&&(f.includes(e)||this.isSelectorSafelisted(e)))s=!0;else{if(e&&this.isSelectorBlocklisted(e))return!1;switch(i.type){case"attribute":s=!!["value","checked","selected","open"].includes(i.attribute)||A(i,t);break;case"class":r=i,s=t.hasClass(r.value);break;case"id":s=V(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.PurgeCSS=R,exports.default=R,exports.defaultOptions=d,exports.mergeExtractorSelectors=x,exports.setOptions=S,exports.standardizeSafelist=y;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("fs"),t=require("glob"),s=require("path"),r=require("postcss"),i=require("postcss-selector-parser"),n=require("util");function o(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function a(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(s){if("default"!==s){var r=Object.getOwnPropertyDescriptor(e,s);Object.defineProperty(t,s,r.get?r:{enumerable:!0,get:function(){return e[s]}})}})),t.default=e,Object.freeze(t)}var c=a(e),u=o(t),l=o(s),d=a(r),h=o(i);function f(e,t){t&&t.forEach(e.add,e)}class p{constructor(e){this.undetermined=new Set,this.attrNames=new Set,this.attrValues=new Set,this.classes=new Set,this.ids=new Set,this.tags=new Set,this.merge(e)}merge(e){return Array.isArray(e)?f(this.undetermined,e):e instanceof p?(f(this.undetermined,e.undetermined),f(this.attrNames,e.attrNames),f(this.attrValues,e.attrValues),f(this.classes,e.classes),f(this.ids,e.ids),f(this.tags,e.tags)):(f(this.undetermined,e.undetermined),e.attributes&&(f(this.attrNames,e.attributes.names),f(this.attrValues,e.attributes.values)),f(this.classes,e.classes),f(this.ids,e.ids),f(this.tags,e.tags)),this}hasAttrName(e){return this.attrNames.has(e)||this.undetermined.has(e)}someAttrValue(e){for(const t of this.attrValues)if(e(t))return!0;for(const t of this.undetermined)if(e(t))return!0;return!1}hasAttrPrefix(e){return this.someAttrValue((t=>t.startsWith(e)))}hasAttrSuffix(e){return this.someAttrValue((t=>t.endsWith(e)))}hasAttrSubstr(e){return e.trim().split(" ").every((e=>this.someAttrValue((t=>t.includes(e)))))}hasAttrValue(e){return this.attrValues.has(e)||this.undetermined.has(e)}hasClass(e){return this.classes.has(e)||this.undetermined.has(e)}hasId(e){return this.ids.has(e)||this.undetermined.has(e)}hasTag(e){return this.tags.has(e)||this.undetermined.has(e)}}const m=["*",":root",":after",":before"],g={css:[],content:[],defaultExtractor:e=>e.match(/[A-Za-z0-9_-]+/g)||[],extractors:[],fontFace:!1,keyframes:!1,rejected:!1,rejectedCss:!1,stdin:!1,stdout:!1,variables:!1,safelist:{standard:[],deep:[],greedy:[],variables:[],keyframes:[]},blocklist:[],skippedContentGlobs:[],dynamicAttributes:[]};function v(e,t){const s=[];return e.replace(t,(function(){const t=arguments,r=Array.prototype.slice.call(t,0,-2);return r.input=t[t.length-1],r.index=t[t.length-2],s.push(r),e})),s}class y{constructor(e){this.nodes=[],this.isUsed=!1,this.value=e}}class S{constructor(){this.nodes=new Map,this.usedVariables=new Set,this.safelist=[]}addVariable(e){const{prop:t}=e;if(this.nodes.has(t)){const s=new y(e),r=this.nodes.get(t)||[];this.nodes.set(t,[...r,s])}else{const s=new y(e);this.nodes.set(t,[s])}}addVariableUsage(e,t){const{prop:s}=e,r=this.nodes.get(s);for(const e of t){const t=e[1];if(this.nodes.has(t)){const e=this.nodes.get(t);null==r||r.forEach((t=>{null==e||e.forEach((e=>t.nodes.push(e)))}))}}}addVariableUsageInProperties(e){for(const t of e){const e=t[1];this.usedVariables.add(e)}}setAsUsed(e){const t=this.nodes.get(e);if(t){const e=[...t];for(;0!==e.length;){const t=e.pop();t&&!t.isUsed&&(t.isUsed=!0,e.push(...t.nodes))}}}removeUnused(){for(const e of this.usedVariables){const t=this.nodes.get(e);if(t)for(const e of t){v(e.value.value,/var\((.+?)[,)]/g).forEach((e=>{this.usedVariables.has(e[1])||this.usedVariables.add(e[1])}))}}for(const e of this.usedVariables)this.setAsUsed(e);for(const[e,t]of this.nodes)for(const s of t)s.isUsed||this.isVariablesSafelisted(e)||s.value.remove()}isVariablesSafelisted(e){return this.safelist.some((t=>"string"==typeof t?t===e:t.test(e)))}}const b={access:n.promisify(c.access),readFile:n.promisify(c.readFile)};function w(e=[]){return Array.isArray(e)?{...g.safelist,standard:e}:{...g.safelist,...e}}async function x(e="purgecss.config.js"){let t;try{const s=l.default.resolve(process.cwd(),e);t=await function(e){return Promise.resolve().then((function(){return a(require(e))}))}(s)}catch(e){throw new Error(`Error loading the config file ${e.message}`)}return{...g,...t,safelist:w(t.safelist)}}async function A(e,t){return new p(await t(e))}function F(e,t){switch(t){case"next":return e.text.includes("purgecss ignore");case"start":return e.text.includes("purgecss start ignore");case"end":return e.text.includes("purgecss end ignore")}}function V(...e){const t=new p([]);return e.forEach(t.merge,t),t}function k(e){return e.replace(/(^["'])|(["']$)/g,"")}function j(e,t){if(!t.hasAttrName(e.attribute))return!1;if(void 0===e.value)return!0;switch(e.operator){case"$=":return t.hasAttrSuffix(e.value);case"~=":case"*=":return t.hasAttrSubstr(e.value);case"=":return t.hasAttrValue(e.value);case"|=":case"^=":return t.hasAttrPrefix(e.value);default:return!0}}function C(e,t){return t.hasId(e.value)}function U(e,t){return t.hasTag(e.value)}function E(e){return"atrule"===(null==e?void 0:e.type)}function R(e){return"rule"===(null==e?void 0:e.type)}class P{constructor(){this.ignore=!1,this.atRules={fontFace:[],keyframes:[]},this.usedAnimations=new Set,this.usedFontFaces=new Set,this.selectorsRemoved=new Set,this.removedNodes=[],this.variablesStructure=new S,this.options=g}collectDeclarationsData(e){const{prop:t,value:s}=e;if(this.options.variables){const r=v(s,/var\((.+?)[,)]/g);t.startsWith("--")?(this.variablesStructure.addVariable(e),r.length>0&&this.variablesStructure.addVariableUsage(e,r)):r.length>0&&this.variablesStructure.addVariableUsageInProperties(r)}if(!this.options.keyframes||"animation"!==t&&"animation-name"!==t)if(this.options.fontFace){if("font-family"===t)for(const e of s.split(",")){const t=k(e.trim());this.usedFontFaces.add(t)}}else;else for(const e of s.split(/[\s,]+/))this.usedAnimations.add(e)}getFileExtractor(e,t){const s=t.find((t=>t.extensions.find((t=>e.endsWith(t)))));return void 0===s?this.options.defaultExtractor:s.extractor}async extractSelectorsFromFiles(e,t){const s=new p([]);for(const r of e){let e=[];try{await b.access(r,c.constants.F_OK),e.push(r)}catch(t){e=u.default.sync(r,{nodir:!0,ignore:this.options.skippedContentGlobs})}for(const r of e){const e=await b.readFile(r,"utf-8"),i=this.getFileExtractor(r,t),n=await A(e,i);s.merge(n)}}return s}async extractSelectorsFromString(e,t){const s=new p([]);for(const{raw:r,extension:i}of e){const e=this.getFileExtractor(`.${i}`,t),n=await A(r,e);s.merge(n)}return s}evaluateAtRule(e){if(this.options.keyframes&&e.name.endsWith("keyframes"))this.atRules.keyframes.push(e);else if(this.options.fontFace&&"font-face"===e.name&&e.nodes)for(const t of e.nodes)"decl"===t.type&&"font-family"===t.prop&&this.atRules.fontFace.push({name:k(t.value),node:e})}evaluateRule(e,t){if(this.ignore)return;const s=e.prev();if(function(e){return"comment"===(null==e?void 0:e.type)}(s)&&F(s,"next"))return void s.remove();if(e.parent&&E(e.parent)&&e.parent.name.endsWith("keyframes"))return;if(!R(e))return;if(function(e){let t=!1;return e.walkComments((e=>{e&&"comment"===e.type&&e.text.includes("purgecss ignore current")&&(t=!0,e.remove())})),t}(e))return;let r=!0;const i=[];if(e.selector=h.default((e=>{e.walk((e=>{"selector"===e.type&&(r=this.shouldKeepSelector(e,t),r||(this.options.rejected&&this.selectorsRemoved.add(e.toString()),this.options.rejectedCss&&i.push(e.toString()),e.remove()))}))})).processSync(e.selector),r&&void 0!==e.nodes)for(const t of e.nodes)"decl"===t.type&&this.collectDeclarationsData(t);const n=e.parent;if(e.selector||e.remove(),function(e){return!!(R(e)&&!e.selector||(null==e?void 0:e.nodes)&&!e.nodes.length||E(e)&&(!e.nodes&&!e.params||!e.params&&e.nodes&&!e.nodes.length))}(n)&&(null==n||n.remove()),this.options.rejectedCss&&i.length>0){const t=e.clone(),s=null==n?void 0:n.clone().removeAll().append(t);t.selectors=i;const r=s||t;this.removedNodes.push(r)}}async getPurgedCSS(e,t){const s=[],r=[];for(const t of e)"string"==typeof t?r.push(...u.default.sync(t,{nodir:!0,ignore:this.options.skippedContentGlobs})):r.push(t);for(const e of r){const r="string"==typeof e?this.options.stdin?e:await b.readFile(e,"utf-8"):e.raw,i=d.parse(r);this.walkThroughCSS(i,t),this.options.fontFace&&this.removeUnusedFontFaces(),this.options.keyframes&&this.removeUnusedKeyframes(),this.options.variables&&this.removeUnusedCSSVariables();const n={css:i.toString(),file:"string"==typeof e?e:e.name};this.options.rejected&&(n.rejected=Array.from(this.selectorsRemoved),this.selectorsRemoved.clear()),this.options.rejectedCss&&(n.rejectedCss=d.root({nodes:this.removedNodes}).toString()),s.push(n)}return s}isKeyframesSafelisted(e){return this.options.safelist.keyframes.some((t=>"string"==typeof t?t===e:t.test(e)))}isSelectorBlocklisted(e){return this.options.blocklist.some((t=>"string"==typeof t?t===e:t.test(e)))}isSelectorSafelisted(e){const t=this.options.safelist.standard.some((t=>"string"==typeof t?t===e:t.test(e))),s=/^::.*/.test(e);return m.includes(e)||s||t}isSelectorSafelistedDeep(e){return this.options.safelist.deep.some((t=>t.test(e)))}isSelectorSafelistedGreedy(e){return this.options.safelist.greedy.some((t=>t.test(e)))}async purge(e){this.options="object"!=typeof e?await x(e):{...g,...e,safelist:w(e.safelist)};const{content:t,css:s,extractors:r,safelist:i}=this.options;this.options.variables&&(this.variablesStructure.safelist=i.variables||[]);const n=t.filter((e=>"string"==typeof e)),o=t.filter((e=>"object"==typeof e)),a=await this.extractSelectorsFromFiles(n,r),c=await this.extractSelectorsFromString(o,r);return this.getPurgedCSS(s,V(a,c))}removeUnusedCSSVariables(){this.variablesStructure.removeUnused()}removeUnusedFontFaces(){for(const{name:e,node:t}of this.atRules.fontFace)this.usedFontFaces.has(e)||t.remove()}removeUnusedKeyframes(){for(const e of this.atRules.keyframes)this.usedAnimations.has(e.params)||this.isKeyframesSafelisted(e.params)||e.remove()}getSelectorValue(e){return"attribute"===e.type&&e.attribute||e.value}shouldKeepSelector(e,t){if(function(e){return e.parent&&"pseudo"===e.parent.type&&e.parent.value.startsWith(":")||!1}(e))return!0;if(this.options.safelist.greedy.length>0){if(e.nodes.map(this.getSelectorValue).some((e=>e&&this.isSelectorSafelistedGreedy(e))))return!0}let s=!1;for(const i of e.nodes){const e=this.getSelectorValue(i);if(e&&this.isSelectorSafelistedDeep(e))return!0;if(e&&(m.includes(e)||this.isSelectorSafelisted(e)))s=!0;else{if(e&&this.isSelectorBlocklisted(e))return!1;switch(i.type){case"attribute":s=!![...this.options.dynamicAttributes,"value","checked","selected","open"].includes(i.attribute)||j(i,t);break;case"class":r=i,s=t.hasClass(r.value);break;case"id":s=C(i,t);break;case"tag":s=U(i,t);break;default:continue}if(!s)return!1}}var r;return s}walkThroughCSS(e,t){e.walk((e=>"rule"===e.type?this.evaluateRule(e,t):"atrule"===e.type?this.evaluateAtRule(e):void("comment"===e.type&&(F(e,"start")?(this.ignore=!0,e.remove()):F(e,"end")&&(this.ignore=!1,e.remove())))))}}exports.PurgeCSS=P,exports.default=P,exports.defaultOptions=g,exports.mergeExtractorSelectors=V,exports.setOptions=x,exports.standardizeSafelist=w;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "purgecss",
3
- "version": "4.0.2",
3
+ "version": "4.1.2",
4
4
  "description": "Remove unused css selectors",
5
5
  "author": "Ffloriel",
6
6
  "homepage": "https://purgecss.com",
@@ -39,10 +39,10 @@
39
39
  "test": "echo \"Error: run tests from root\" && exit 1"
40
40
  },
41
41
  "dependencies": {
42
- "commander": "^6.0.0",
43
- "glob": "^7.0.0",
44
- "postcss": "^8.2.1",
45
- "postcss-selector-parser": "^6.0.2"
42
+ "commander": "^8.0.0",
43
+ "glob": "^7.1.7",
44
+ "postcss": "^8.3.5",
45
+ "postcss-selector-parser": "^6.0.6"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/glob": "^7.1.1"
@@ -50,5 +50,9 @@
50
50
  "bugs": {
51
51
  "url": "https://github.com/FullHuman/purgecss/issues"
52
52
  },
53
- "gitHead": "d05d119a44c085d4bc5b1421dab8dd9c12b01e2d"
53
+ "publishConfig": {
54
+ "access": "public",
55
+ "registry": "https://registry.npmjs.org/"
56
+ },
57
+ "gitHead": "1329d96b0ad17e9b2b4d604d1a689856da176a59"
54
58
  }