purgecss 2.0.6 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/purgecss +23 -6
- package/lib/purgecss.d.ts +86 -7
- package/lib/purgecss.esm.d.ts +86 -7
- package/lib/purgecss.esm.js +1 -1
- package/lib/purgecss.js +1 -1
- package/package.json +7 -7
- package/LICENSE +0 -21
package/bin/purgecss
CHANGED
|
@@ -7,6 +7,14 @@ function getList(list) {
|
|
|
7
7
|
return list.split(',')
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
async function writeCSSToFile(filePath, css) {
|
|
11
|
+
try {
|
|
12
|
+
await fs.promises.writeFile(filePath, css);
|
|
13
|
+
} catch(err) {
|
|
14
|
+
console.error(err.message);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
10
18
|
program
|
|
11
19
|
.usage('--css <css> --content <content> [options]')
|
|
12
20
|
.option('-con, --content <files>', 'glob of content files (comma separated)', getList)
|
|
@@ -41,16 +49,25 @@ if (!program.config && !(program.content && program.css)) {
|
|
|
41
49
|
if (program.variables) options.variables = program.variables;
|
|
42
50
|
if (program.whitelist) options.whitelist = program.whitelist;
|
|
43
51
|
|
|
52
|
+
// if (!options.css) {
|
|
53
|
+
// options.css = [{
|
|
54
|
+
// raw: stdInCSS
|
|
55
|
+
// }]
|
|
56
|
+
// }
|
|
57
|
+
|
|
44
58
|
const purged = await new PurgeCSS().purge(options);
|
|
59
|
+
|
|
60
|
+
const output = options.output || program.output;
|
|
45
61
|
// output results in specified directory
|
|
46
|
-
if (
|
|
62
|
+
if (output) {
|
|
63
|
+
if (purged.length === 1 && output.endsWith('.css')) {
|
|
64
|
+
await writeCSSToFile(output, purged[0].css)
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
47
68
|
for (const purgedResult of purged) {
|
|
48
69
|
const fileName = purgedResult.file.split("/").pop();
|
|
49
|
-
|
|
50
|
-
fs.promises.writeFile(`${program.output}/${fileName}`, purgedResult.css);
|
|
51
|
-
} catch(err) {
|
|
52
|
-
console.error(err.message);
|
|
53
|
-
}
|
|
70
|
+
await writeCSSToFile(`${output}/${fileName}`, purgedResult.css);
|
|
54
71
|
}
|
|
55
72
|
} else {
|
|
56
73
|
console.log(JSON.stringify(purged));
|
package/lib/purgecss.d.ts
CHANGED
|
@@ -60,6 +60,25 @@ interface ResultPurge {
|
|
|
60
60
|
rejected?: string[];
|
|
61
61
|
}
|
|
62
62
|
declare const defaultOptions: Options;
|
|
63
|
+
declare class ExtractorResultSets {
|
|
64
|
+
private undetermined;
|
|
65
|
+
private attrNames;
|
|
66
|
+
private attrValues;
|
|
67
|
+
private classes;
|
|
68
|
+
private ids;
|
|
69
|
+
private tags;
|
|
70
|
+
constructor(er: ExtractorResult);
|
|
71
|
+
merge(that: ExtractorResult | ExtractorResultSets): this;
|
|
72
|
+
hasAttrName(name: string): boolean;
|
|
73
|
+
private someAttrValue;
|
|
74
|
+
hasAttrPrefix(prefix: string): boolean;
|
|
75
|
+
hasAttrSuffix(suffix: string): boolean;
|
|
76
|
+
hasAttrSubstr(substr: string): boolean;
|
|
77
|
+
hasAttrValue(value: string): boolean;
|
|
78
|
+
hasClass(name: string): boolean;
|
|
79
|
+
hasId(id: string): boolean;
|
|
80
|
+
hasTag(tag: string): boolean;
|
|
81
|
+
}
|
|
63
82
|
/**
|
|
64
83
|
* Load the configuration file from the path
|
|
65
84
|
* @param configFile Path of the config file
|
|
@@ -70,7 +89,7 @@ declare function setOptions(configFile?: string): Promise<Options>;
|
|
|
70
89
|
* @param extractorSelectorsA extractor selectors A
|
|
71
90
|
* @param extractorSelectorsB extractor selectors B
|
|
72
91
|
*/
|
|
73
|
-
declare function mergeExtractorSelectors(
|
|
92
|
+
declare function mergeExtractorSelectors(...extractors: (ExtractorResultDetailed | ExtractorResultSets)[]): ExtractorResultSets;
|
|
74
93
|
declare class PurgeCSS {
|
|
75
94
|
private ignore;
|
|
76
95
|
private atRules;
|
|
@@ -80,6 +99,11 @@ declare class PurgeCSS {
|
|
|
80
99
|
private variablesStructure;
|
|
81
100
|
options: Options;
|
|
82
101
|
private collectDeclarationsData;
|
|
102
|
+
/**
|
|
103
|
+
* Get the extractor corresponding to the extension file
|
|
104
|
+
* @param filename Name of the file
|
|
105
|
+
* @param extractors Array of extractors definition
|
|
106
|
+
*/
|
|
83
107
|
/**
|
|
84
108
|
* Get the extractor corresponding to the extension file
|
|
85
109
|
* @param filename Name of the file
|
|
@@ -91,18 +115,37 @@ declare class PurgeCSS {
|
|
|
91
115
|
* @param files Array of files path or glob pattern
|
|
92
116
|
* @param extractors Array of extractors
|
|
93
117
|
*/
|
|
94
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Extract the selectors present in the files using a purgecss extractor
|
|
120
|
+
* @param files Array of files path or glob pattern
|
|
121
|
+
* @param extractors Array of extractors
|
|
122
|
+
*/
|
|
123
|
+
extractSelectorsFromFiles(files: string[], extractors: Extractors[]): Promise<ExtractorResultSets>;
|
|
124
|
+
/**
|
|
125
|
+
* Extract the selectors present in the passed string using a PurgeCSS extractor
|
|
126
|
+
* @param content Array of content
|
|
127
|
+
* @param extractors Array of extractors
|
|
128
|
+
*/
|
|
95
129
|
/**
|
|
96
130
|
* Extract the selectors present in the passed string using a PurgeCSS extractor
|
|
97
131
|
* @param content Array of content
|
|
98
132
|
* @param extractors Array of extractors
|
|
99
133
|
*/
|
|
100
|
-
extractSelectorsFromString(content: RawContent[], extractors: Extractors[]):
|
|
134
|
+
extractSelectorsFromString(content: RawContent[], extractors: Extractors[]): Promise<ExtractorResultSets>;
|
|
135
|
+
/**
|
|
136
|
+
* Evaluate at-rule and register it for future reference
|
|
137
|
+
* @param node node of postcss AST
|
|
138
|
+
*/
|
|
101
139
|
/**
|
|
102
140
|
* Evaluate at-rule and register it for future reference
|
|
103
141
|
* @param node node of postcss AST
|
|
104
142
|
*/
|
|
105
143
|
private evaluateAtRule;
|
|
144
|
+
/**
|
|
145
|
+
* Evaluate css selector and decide if it should be removed or not
|
|
146
|
+
* @param node node of postcss AST
|
|
147
|
+
* @param selectors selectors used in content files
|
|
148
|
+
*/
|
|
106
149
|
/**
|
|
107
150
|
* Evaluate css selector and decide if it should be removed or not
|
|
108
151
|
* @param node node of postcss AST
|
|
@@ -114,12 +157,25 @@ declare class PurgeCSS {
|
|
|
114
157
|
* @param cssOptions css options, files or raw strings
|
|
115
158
|
* @param selectors set of extracted css selectors
|
|
116
159
|
*/
|
|
117
|
-
|
|
160
|
+
/**
|
|
161
|
+
* Get the purged version of the css based on the files
|
|
162
|
+
* @param cssOptions css options, files or raw strings
|
|
163
|
+
* @param selectors set of extracted css selectors
|
|
164
|
+
*/
|
|
165
|
+
getPurgedCSS(cssOptions: Array<string | RawCSS>, selectors: ExtractorResultSets): Promise<ResultPurge[]>;
|
|
166
|
+
/**
|
|
167
|
+
* Check if the selector is whitelisted by the option whitelist or whitelistPatterns
|
|
168
|
+
* @param selector css selector
|
|
169
|
+
*/
|
|
118
170
|
/**
|
|
119
171
|
* Check if the selector is whitelisted by the option whitelist or whitelistPatterns
|
|
120
172
|
* @param selector css selector
|
|
121
173
|
*/
|
|
122
174
|
private isSelectorWhitelisted;
|
|
175
|
+
/**
|
|
176
|
+
* Check if the selector is whitelisted by the whitelistPatternsChildren option
|
|
177
|
+
* @param selector selector
|
|
178
|
+
*/
|
|
123
179
|
/**
|
|
124
180
|
* Check if the selector is whitelisted by the whitelistPatternsChildren option
|
|
125
181
|
* @param selector selector
|
|
@@ -127,24 +183,42 @@ declare class PurgeCSS {
|
|
|
127
183
|
private isSelectorWhitelistedChildren;
|
|
128
184
|
/**
|
|
129
185
|
* Remove unused css
|
|
130
|
-
* @param
|
|
186
|
+
* @param userOptions PurgeCSS options
|
|
187
|
+
*/
|
|
188
|
+
/**
|
|
189
|
+
* Remove unused css
|
|
190
|
+
* @param userOptions PurgeCSS options
|
|
131
191
|
*/
|
|
132
192
|
purge(userOptions: UserDefinedOptions | string | undefined): Promise<ResultPurge[]>;
|
|
193
|
+
/**
|
|
194
|
+
* Remove unused CSS variables
|
|
195
|
+
*/
|
|
133
196
|
/**
|
|
134
197
|
* Remove unused CSS variables
|
|
135
198
|
*/
|
|
136
199
|
removeUnusedCSSVariables(): void;
|
|
200
|
+
/**
|
|
201
|
+
* Remove unused font-faces
|
|
202
|
+
*/
|
|
137
203
|
/**
|
|
138
204
|
* Remove unused font-faces
|
|
139
205
|
*/
|
|
140
206
|
removeUnusedFontFaces(): void;
|
|
207
|
+
/**
|
|
208
|
+
* Remove unused keyframes
|
|
209
|
+
*/
|
|
141
210
|
/**
|
|
142
211
|
* Remove unused keyframes
|
|
143
212
|
*/
|
|
144
213
|
removeUnusedKeyframes(): void;
|
|
145
214
|
/**
|
|
146
215
|
* Determine if the selector should be kept, based on the selectors found in the files
|
|
147
|
-
* @param
|
|
216
|
+
* @param selector set of css selectors found in the content files or string
|
|
217
|
+
* @param selectorsFromExtractor selectors in the css rule
|
|
218
|
+
*/
|
|
219
|
+
/**
|
|
220
|
+
* Determine if the selector should be kept, based on the selectors found in the files
|
|
221
|
+
* @param selector set of css selectors found in the content files or string
|
|
148
222
|
* @param selectorsFromExtractor selectors in the css rule
|
|
149
223
|
*/
|
|
150
224
|
private shouldKeepSelector;
|
|
@@ -153,6 +227,11 @@ declare class PurgeCSS {
|
|
|
153
227
|
* @param root root node of the postcss AST
|
|
154
228
|
* @param selectors selectors used in content files
|
|
155
229
|
*/
|
|
156
|
-
|
|
230
|
+
/**
|
|
231
|
+
* Walk through the CSS AST and remove unused CSS
|
|
232
|
+
* @param root root node of the postcss AST
|
|
233
|
+
* @param selectors selectors used in content files
|
|
234
|
+
*/
|
|
235
|
+
walkThroughCSS(root: postcss.Root, selectors: ExtractorResultSets): void;
|
|
157
236
|
}
|
|
158
237
|
export { PurgeCSS as default, PurgeCSS, defaultOptions, setOptions, mergeExtractorSelectors };
|
package/lib/purgecss.esm.d.ts
CHANGED
|
@@ -60,6 +60,25 @@ interface ResultPurge {
|
|
|
60
60
|
rejected?: string[];
|
|
61
61
|
}
|
|
62
62
|
declare const defaultOptions: Options;
|
|
63
|
+
declare class ExtractorResultSets {
|
|
64
|
+
private undetermined;
|
|
65
|
+
private attrNames;
|
|
66
|
+
private attrValues;
|
|
67
|
+
private classes;
|
|
68
|
+
private ids;
|
|
69
|
+
private tags;
|
|
70
|
+
constructor(er: ExtractorResult);
|
|
71
|
+
merge(that: ExtractorResult | ExtractorResultSets): this;
|
|
72
|
+
hasAttrName(name: string): boolean;
|
|
73
|
+
private someAttrValue;
|
|
74
|
+
hasAttrPrefix(prefix: string): boolean;
|
|
75
|
+
hasAttrSuffix(suffix: string): boolean;
|
|
76
|
+
hasAttrSubstr(substr: string): boolean;
|
|
77
|
+
hasAttrValue(value: string): boolean;
|
|
78
|
+
hasClass(name: string): boolean;
|
|
79
|
+
hasId(id: string): boolean;
|
|
80
|
+
hasTag(tag: string): boolean;
|
|
81
|
+
}
|
|
63
82
|
/**
|
|
64
83
|
* Load the configuration file from the path
|
|
65
84
|
* @param configFile Path of the config file
|
|
@@ -70,7 +89,7 @@ declare function setOptions(configFile?: string): Promise<Options>;
|
|
|
70
89
|
* @param extractorSelectorsA extractor selectors A
|
|
71
90
|
* @param extractorSelectorsB extractor selectors B
|
|
72
91
|
*/
|
|
73
|
-
declare function mergeExtractorSelectors(
|
|
92
|
+
declare function mergeExtractorSelectors(...extractors: (ExtractorResultDetailed | ExtractorResultSets)[]): ExtractorResultSets;
|
|
74
93
|
declare class PurgeCSS {
|
|
75
94
|
private ignore;
|
|
76
95
|
private atRules;
|
|
@@ -80,6 +99,11 @@ declare class PurgeCSS {
|
|
|
80
99
|
private variablesStructure;
|
|
81
100
|
options: Options;
|
|
82
101
|
private collectDeclarationsData;
|
|
102
|
+
/**
|
|
103
|
+
* Get the extractor corresponding to the extension file
|
|
104
|
+
* @param filename Name of the file
|
|
105
|
+
* @param extractors Array of extractors definition
|
|
106
|
+
*/
|
|
83
107
|
/**
|
|
84
108
|
* Get the extractor corresponding to the extension file
|
|
85
109
|
* @param filename Name of the file
|
|
@@ -91,18 +115,37 @@ declare class PurgeCSS {
|
|
|
91
115
|
* @param files Array of files path or glob pattern
|
|
92
116
|
* @param extractors Array of extractors
|
|
93
117
|
*/
|
|
94
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Extract the selectors present in the files using a purgecss extractor
|
|
120
|
+
* @param files Array of files path or glob pattern
|
|
121
|
+
* @param extractors Array of extractors
|
|
122
|
+
*/
|
|
123
|
+
extractSelectorsFromFiles(files: string[], extractors: Extractors[]): Promise<ExtractorResultSets>;
|
|
124
|
+
/**
|
|
125
|
+
* Extract the selectors present in the passed string using a PurgeCSS extractor
|
|
126
|
+
* @param content Array of content
|
|
127
|
+
* @param extractors Array of extractors
|
|
128
|
+
*/
|
|
95
129
|
/**
|
|
96
130
|
* Extract the selectors present in the passed string using a PurgeCSS extractor
|
|
97
131
|
* @param content Array of content
|
|
98
132
|
* @param extractors Array of extractors
|
|
99
133
|
*/
|
|
100
|
-
extractSelectorsFromString(content: RawContent[], extractors: Extractors[]):
|
|
134
|
+
extractSelectorsFromString(content: RawContent[], extractors: Extractors[]): Promise<ExtractorResultSets>;
|
|
135
|
+
/**
|
|
136
|
+
* Evaluate at-rule and register it for future reference
|
|
137
|
+
* @param node node of postcss AST
|
|
138
|
+
*/
|
|
101
139
|
/**
|
|
102
140
|
* Evaluate at-rule and register it for future reference
|
|
103
141
|
* @param node node of postcss AST
|
|
104
142
|
*/
|
|
105
143
|
private evaluateAtRule;
|
|
144
|
+
/**
|
|
145
|
+
* Evaluate css selector and decide if it should be removed or not
|
|
146
|
+
* @param node node of postcss AST
|
|
147
|
+
* @param selectors selectors used in content files
|
|
148
|
+
*/
|
|
106
149
|
/**
|
|
107
150
|
* Evaluate css selector and decide if it should be removed or not
|
|
108
151
|
* @param node node of postcss AST
|
|
@@ -114,12 +157,25 @@ declare class PurgeCSS {
|
|
|
114
157
|
* @param cssOptions css options, files or raw strings
|
|
115
158
|
* @param selectors set of extracted css selectors
|
|
116
159
|
*/
|
|
117
|
-
|
|
160
|
+
/**
|
|
161
|
+
* Get the purged version of the css based on the files
|
|
162
|
+
* @param cssOptions css options, files or raw strings
|
|
163
|
+
* @param selectors set of extracted css selectors
|
|
164
|
+
*/
|
|
165
|
+
getPurgedCSS(cssOptions: Array<string | RawCSS>, selectors: ExtractorResultSets): Promise<ResultPurge[]>;
|
|
166
|
+
/**
|
|
167
|
+
* Check if the selector is whitelisted by the option whitelist or whitelistPatterns
|
|
168
|
+
* @param selector css selector
|
|
169
|
+
*/
|
|
118
170
|
/**
|
|
119
171
|
* Check if the selector is whitelisted by the option whitelist or whitelistPatterns
|
|
120
172
|
* @param selector css selector
|
|
121
173
|
*/
|
|
122
174
|
private isSelectorWhitelisted;
|
|
175
|
+
/**
|
|
176
|
+
* Check if the selector is whitelisted by the whitelistPatternsChildren option
|
|
177
|
+
* @param selector selector
|
|
178
|
+
*/
|
|
123
179
|
/**
|
|
124
180
|
* Check if the selector is whitelisted by the whitelistPatternsChildren option
|
|
125
181
|
* @param selector selector
|
|
@@ -127,24 +183,42 @@ declare class PurgeCSS {
|
|
|
127
183
|
private isSelectorWhitelistedChildren;
|
|
128
184
|
/**
|
|
129
185
|
* Remove unused css
|
|
130
|
-
* @param
|
|
186
|
+
* @param userOptions PurgeCSS options
|
|
187
|
+
*/
|
|
188
|
+
/**
|
|
189
|
+
* Remove unused css
|
|
190
|
+
* @param userOptions PurgeCSS options
|
|
131
191
|
*/
|
|
132
192
|
purge(userOptions: UserDefinedOptions | string | undefined): Promise<ResultPurge[]>;
|
|
193
|
+
/**
|
|
194
|
+
* Remove unused CSS variables
|
|
195
|
+
*/
|
|
133
196
|
/**
|
|
134
197
|
* Remove unused CSS variables
|
|
135
198
|
*/
|
|
136
199
|
removeUnusedCSSVariables(): void;
|
|
200
|
+
/**
|
|
201
|
+
* Remove unused font-faces
|
|
202
|
+
*/
|
|
137
203
|
/**
|
|
138
204
|
* Remove unused font-faces
|
|
139
205
|
*/
|
|
140
206
|
removeUnusedFontFaces(): void;
|
|
207
|
+
/**
|
|
208
|
+
* Remove unused keyframes
|
|
209
|
+
*/
|
|
141
210
|
/**
|
|
142
211
|
* Remove unused keyframes
|
|
143
212
|
*/
|
|
144
213
|
removeUnusedKeyframes(): void;
|
|
145
214
|
/**
|
|
146
215
|
* Determine if the selector should be kept, based on the selectors found in the files
|
|
147
|
-
* @param
|
|
216
|
+
* @param selector set of css selectors found in the content files or string
|
|
217
|
+
* @param selectorsFromExtractor selectors in the css rule
|
|
218
|
+
*/
|
|
219
|
+
/**
|
|
220
|
+
* Determine if the selector should be kept, based on the selectors found in the files
|
|
221
|
+
* @param selector set of css selectors found in the content files or string
|
|
148
222
|
* @param selectorsFromExtractor selectors in the css rule
|
|
149
223
|
*/
|
|
150
224
|
private shouldKeepSelector;
|
|
@@ -153,6 +227,11 @@ declare class PurgeCSS {
|
|
|
153
227
|
* @param root root node of the postcss AST
|
|
154
228
|
* @param selectors selectors used in content files
|
|
155
229
|
*/
|
|
156
|
-
|
|
230
|
+
/**
|
|
231
|
+
* Walk through the CSS AST and remove unused CSS
|
|
232
|
+
* @param root root node of the postcss AST
|
|
233
|
+
* @param selectors selectors used in content files
|
|
234
|
+
*/
|
|
235
|
+
walkThroughCSS(root: postcss.Root, selectors: ExtractorResultSets): void;
|
|
157
236
|
}
|
|
158
237
|
export { PurgeCSS as default, PurgeCSS, defaultOptions, setOptions, mergeExtractorSelectors };
|
package/lib/purgecss.esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{parse as
|
|
1
|
+
import{parse as t}from"postcss";import e from"postcss-selector-parser";import{access as s,readFile as r,constants as i}from"fs";import{promisify as n}from"util";import a from"glob";import o from"path";const c={css:[],content:[],defaultExtractor:t=>t.match(/[A-Za-z0-9_-]+/g)||[],extractors:[],fontFace:!1,keyframes:!1,rejected:!1,stdin:!1,stdout:!1,variables:!1,whitelist:[],whitelistPatterns:[],whitelistPatternsChildren:[]},u=["*","::-webkit-scrollbar","::selection",":root","::before","::after"];class h{constructor(t){this.nodes=[],this.isUsed=!1,this.value=t}}class l{constructor(){this.nodes=new Map,this.usedVariables=new Set}addVariable(t){const{prop:e}=t;if(!this.nodes.has(e)){const s=new h(t);this.nodes.set(e,s)}}addVariableUsage(t,e){const{prop:s}=t,r=this.nodes.get(s);for(const t of e){const e=t[1];if(this.nodes.has(e)){const t=this.nodes.get(e);null==r||r.nodes.push(t)}}}addVariableUsageInProperties(t){for(const e of t){const t=e[1];this.usedVariables.add(t)}}setAsUsed(t){const e=[this.nodes.get(t)];for(;0!==e.length;){const t=e.pop();t&&!t.isUsed&&(t.isUsed=!0,e.push(...t.nodes))}}removeUnused(){for(const t of this.usedVariables)this.setAsUsed(t);for(const[,t]of this.nodes)t.isUsed||t.value.remove()}}function d(t,e){e&&e.forEach(t.add,t)}class f{constructor(t){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(t)}merge(t){return Array.isArray(t)?d(this.undetermined,t):t instanceof f?(d(this.undetermined,t.undetermined),d(this.attrNames,t.attrNames),d(this.attrValues,t.attrValues),d(this.classes,t.classes),d(this.ids,t.ids),d(this.tags,t.tags)):(d(this.undetermined,t.undetermined),t.attributes&&(d(this.attrNames,t.attributes.names),d(this.attrValues,t.attributes.values)),d(this.classes,t.classes),d(this.ids,t.ids),d(this.tags,t.tags)),this}hasAttrName(t){return this.attrNames.has(t)||this.undetermined.has(t)}someAttrValue(t){for(const e of this.attrValues)if(t(e))return!0;for(const e of this.undetermined)if(t(e))return!0;return!1}hasAttrPrefix(t){return this.someAttrValue(e=>e.startsWith(t))}hasAttrSuffix(t){return this.someAttrValue(e=>e.endsWith(t))}hasAttrSubstr(t){return this.someAttrValue(e=>e.includes(t))}hasAttrValue(t){return this.attrValues.has(t)||this.undetermined.has(t)}hasClass(t){return this.classes.has(t)||this.undetermined.has(t)}hasId(t){return this.ids.has(t)||this.undetermined.has(t)}hasTag(t){return this.tags.has(t)||this.undetermined.has(t)}}const m={access:n(s),readFile:n(r)};async function p(t="purgecss.config.js"){let e;try{const s=o.join(process.cwd(),t);e=await import(s)}catch(t){throw new Error(`Error loading the config file ${t.message}`)}return{...c,...e}}async function g(t,e){return new f(await e(t))}function v(t,e){switch(e){case"next":return t.text.includes("purgecss ignore");case"start":return t.text.includes("purgecss start ignore");case"end":return t.text.includes("purgecss end ignore")}}function y(...t){const e=new f([]);return t.forEach(e.merge,e),e}function w(t){return t.replace(/(^["'])|(["']$)/g,"")}function S(t,e){if(!e.hasAttrName(t.attribute))return!1;if(void 0===t.value)return!0;switch(t.operator){case"$=":return e.hasAttrSuffix(t.value);case"~=":case"*=":return e.hasAttrSubstr(t.value);case"=":return e.hasAttrValue(t.value);case"|=":case"^=":return e.hasAttrPrefix(t.value);default:return!0}}function b(t,e){return e.hasId(t.value)}function F(t,e){return e.hasTag(t.value)}class x{constructor(){this.ignore=!1,this.atRules={fontFace:[],keyframes:[]},this.usedAnimations=new Set,this.usedFontFaces=new Set,this.selectorsRemoved=new Set,this.variablesStructure=new l,this.options=c}collectDeclarationsData(t){const{prop:e,value:s}=t;if(this.options.variables){const r=function(t,e){const s=[];return t.replace(e,(function(){const e=arguments,r=Array.prototype.slice.call(e,0,-2);return r.input=e[e.length-1],r.index=e[e.length-2],s.push(r),t})),s}(s,/var\((.+?)[,)]/g);e.startsWith("--")?(this.variablesStructure.addVariable(t),r.length>0&&this.variablesStructure.addVariableUsage(t,r)):r.length>0&&this.variablesStructure.addVariableUsageInProperties(r)}if(!this.options.keyframes||"animation"!==e&&"animation-name"!==e)if(this.options.fontFace){if("font-family"===e)for(const t of s.split(",")){const e=w(t.trim());this.usedFontFaces.add(e)}}else;else for(const t of s.split(/[\s,]+/))this.usedAnimations.add(t)}getFileExtractor(t,e){const s=e.find(e=>e.extensions.find(e=>t.endsWith(e)));return void 0===s?this.options.defaultExtractor:s.extractor}async extractSelectorsFromFiles(t,e){const s=new f([]);for(const r of t){let t=[];try{await m.access(r,i.F_OK),t.push(r)}catch(e){t=a.sync(r)}for(const r of t){const t=await m.readFile(r,"utf-8"),i=this.getFileExtractor(r,e),n=await g(t,i);s.merge(n)}}return s}async extractSelectorsFromString(t,e){const s=new f([]);for(const{raw:r,extension:i}of t){const t=this.getFileExtractor(`.${i}`,e),n=await g(r,t);s.merge(n)}return s}evaluateAtRule(t){if(this.options.keyframes&&t.name.endsWith("keyframes"))this.atRules.keyframes.push(t);else if(this.options.fontFace&&"font-face"===t.name&&t.nodes)for(const e of t.nodes)"decl"===e.type&&"font-family"===e.prop&&this.atRules.fontFace.push({name:w(e.value),node:t})}async evaluateRule(t,s){if(this.ignore)return;const r=t.prev();if(r&&"comment"===r.type&&v(r,"next"))return void r.remove();if(t.parent&&"atrule"===t.parent.type&&"keyframes"===t.parent.name)return;if("rule"!==t.type)return;if(function(t){let e=!1;return t.walkComments(t=>{t&&"comment"===t.type&&t.text.includes("purgecss ignore current")&&(e=!0,t.remove())}),e}(t))return;let i=!0;if(t.selector=e(t=>{t.walk(t=>{"selector"===t.type&&(i=this.shouldKeepSelector(t,s),i||(this.options.rejected&&this.selectorsRemoved.add(t.toString()),t.remove()))})}).processSync(t.selector),i&&void 0!==t.nodes)for(const e of t.nodes)"decl"===e.type&&this.collectDeclarationsData(e);const n=t.parent;t.selector||t.remove(),function(t){return!!("rule"===t.type&&!t.selector||t.nodes&&!t.nodes.length||"atrule"===t.type&&(!t.nodes&&!t.params||!t.params&&t.nodes&&!t.nodes.length))}(n)&&n.remove()}async getPurgedCSS(e,s){const r=[],i=[];for(const t of e)"string"==typeof t?i.push(...a.sync(t)):i.push(t);for(const e of i){const i="string"==typeof e?this.options.stdin?e:await m.readFile(e,"utf-8"):e.raw,n=t(i);this.walkThroughCSS(n,s),this.options.fontFace&&this.removeUnusedFontFaces(),this.options.keyframes&&this.removeUnusedKeyframes(),this.options.variables&&this.removeUnusedCSSVariables();const a={css:n.toString(),file:"string"==typeof e?e:void 0};"string"==typeof e&&(a.file=e),this.options.rejected&&(a.rejected=Array.from(this.selectorsRemoved),this.selectorsRemoved.clear()),r.push(a)}return r}isSelectorWhitelisted(t){return u.includes(t)||this.options.whitelist&&this.options.whitelist.some(e=>e===t)||this.options.whitelistPatterns&&this.options.whitelistPatterns.some(e=>e.test(t))}isSelectorWhitelistedChildren(t){return this.options.whitelistPatternsChildren&&this.options.whitelistPatternsChildren.some(e=>e.test(t))}async purge(t){this.options="object"!=typeof t?await p(t):{...c,...t};const{content:e,css:s,extractors:r}=this.options,i=e.filter(t=>"string"==typeof t),n=e.filter(t=>"object"==typeof t),a=await this.extractSelectorsFromFiles(i,r),o=await this.extractSelectorsFromString(n,r);return this.getPurgedCSS(s,y(a,o))}removeUnusedCSSVariables(){this.variablesStructure.removeUnused()}removeUnusedFontFaces(){for(const{name:t,node:e}of this.atRules.fontFace)this.usedFontFaces.has(t)||e.remove()}removeUnusedKeyframes(){for(const t of this.atRules.keyframes)this.usedAnimations.has(t.params)||t.remove()}shouldKeepSelector(t,e){if(function(t){return t.parent&&"pseudo"===t.parent.type&&t.parent.value.startsWith(":")||!1}(t))return!0;let s=!1;for(const i of t.nodes){const t="attribute"===i.type&&i.attribute||i.value;if(t&&this.isSelectorWhitelistedChildren(t))return!0;if(t&&(u.includes(t)||this.isSelectorWhitelisted(t)))s=!0;else{switch(i.type){case"attribute":s=!!["value","checked","selected","open"].includes(i.attribute)||S(i,e);break;case"class":r=i,s=e.hasClass(r.value);break;case"id":s=b(i,e);break;case"tag":s=F(i,e)}if(!s)return!1}}var r;return s}walkThroughCSS(t,e){t.walk(t=>"rule"===t.type?this.evaluateRule(t,e):"atrule"===t.type?this.evaluateAtRule(t):void("comment"===t.type&&(v(t,"start")?(this.ignore=!0,t.remove()):v(t,"end")&&(this.ignore=!1,t.remove()))))}}export default x;export{x as PurgeCSS,c as defaultOptions,y as mergeExtractorSelectors,p as setOptions};
|
package/lib/purgecss.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";function
|
|
1
|
+
"use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e.default:e}Object.defineProperty(exports,"__esModule",{value:!0});var t=require("postcss"),s=e(require("postcss-selector-parser")),r=require("fs"),i=require("util"),n=e(require("glob")),a=e(require("path"));const o={css:[],content:[],defaultExtractor:e=>e.match(/[A-Za-z0-9_-]+/g)||[],extractors:[],fontFace:!1,keyframes:!1,rejected:!1,stdin:!1,stdout:!1,variables:!1,whitelist:[],whitelistPatterns:[],whitelistPatternsChildren:[]},c=["*","::-webkit-scrollbar","::selection",":root","::before","::after"];class u{constructor(e){this.nodes=[],this.isUsed=!1,this.value=e}}class l{constructor(){this.nodes=new Map,this.usedVariables=new Set}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]of this.nodes)e.isUsed||e.value.remove()}}function h(e,t){t&&t.forEach(e.add,e)}class d{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)?h(this.undetermined,e):e instanceof d?(h(this.undetermined,e.undetermined),h(this.attrNames,e.attrNames),h(this.attrValues,e.attrValues),h(this.classes,e.classes),h(this.ids,e.ids),h(this.tags,e.tags)):(h(this.undetermined,e.undetermined),e.attributes&&(h(this.attrNames,e.attributes.names),h(this.attrValues,e.attributes.values)),h(this.classes,e.classes),h(this.ids,e.ids),h(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 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 f={access:i.promisify(r.access),readFile:i.promisify(r.readFile)};async function p(e="purgecss.config.js"){let t;try{const s=a.join(process.cwd(),e);t=await new Promise((function(e){e(function(e){if(e&&e.__esModule)return e;var t={};return e&&Object.keys(e).forEach((function(s){var r=Object.getOwnPropertyDescriptor(e,s);Object.defineProperty(t,s,r.get?r:{enumerable:!0,get:function(){return e[s]}})})),t.default=e,t}(require(s)))}))}catch(e){throw new Error(`Error loading the config file ${e.message}`)}return{...o,...t}}async function m(e,t){return new d(await t(e))}function g(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 d([]);return e.forEach(t.merge,t),t}function y(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 S(e,t){return t.hasId(e.value)}function b(e,t){return t.hasTag(e.value)}class x{constructor(){this.ignore=!1,this.atRules={fontFace:[],keyframes:[]},this.usedAnimations=new Set,this.usedFontFaces=new Set,this.selectorsRemoved=new Set,this.variablesStructure=new l,this.options=o}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=y(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 d([]);for(const i of e){let e=[];try{await f.access(i,r.constants.F_OK),e.push(i)}catch(t){e=n.sync(i)}for(const r of e){const e=await f.readFile(r,"utf-8"),i=this.getFileExtractor(r,t),n=await m(e,i);s.merge(n)}}return s}async extractSelectorsFromString(e,t){const s=new d([]);for(const{raw:r,extension:i}of e){const e=this.getFileExtractor(`.${i}`,t),n=await m(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:y(t.value),node:e})}async evaluateRule(e,t){if(this.ignore)return;const r=e.prev();if(r&&"comment"===r.type&&g(r,"next"))return void r.remove();if(e.parent&&"atrule"===e.parent.type&&"keyframes"===e.parent.name)return;if("rule"!==e.type)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=s(e=>{e.walk(e=>{"selector"===e.type&&(i=this.shouldKeepSelector(e,t),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 n=e.parent;e.selector||e.remove(),function(e){return!!("rule"===e.type&&!e.selector||e.nodes&&!e.nodes.length||"atrule"===e.type&&(!e.nodes&&!e.params||!e.params&&e.nodes&&!e.nodes.length))}(n)&&n.remove()}async getPurgedCSS(e,s){const r=[],i=[];for(const t of e)"string"==typeof t?i.push(...n.sync(t)):i.push(t);for(const e of i){const i="string"==typeof e?this.options.stdin?e:await f.readFile(e,"utf-8"):e.raw,n=t.parse(i);this.walkThroughCSS(n,s),this.options.fontFace&&this.removeUnusedFontFaces(),this.options.keyframes&&this.removeUnusedKeyframes(),this.options.variables&&this.removeUnusedCSSVariables();const a={css:n.toString(),file:"string"==typeof e?e:void 0};"string"==typeof e&&(a.file=e),this.options.rejected&&(a.rejected=Array.from(this.selectorsRemoved),this.selectorsRemoved.clear()),r.push(a)}return r}isSelectorWhitelisted(e){return c.includes(e)||this.options.whitelist&&this.options.whitelist.some(t=>t===e)||this.options.whitelistPatterns&&this.options.whitelistPatterns.some(t=>t.test(e))}isSelectorWhitelistedChildren(e){return this.options.whitelistPatternsChildren&&this.options.whitelistPatternsChildren.some(t=>t.test(e))}async purge(e){this.options="object"!=typeof e?await p(e):{...o,...e};const{content:t,css:s,extractors:r}=this.options,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,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)||e.remove()}shouldKeepSelector(e,t){if(function(e){return e.parent&&"pseudo"===e.parent.type&&e.parent.value.startsWith(":")||!1}(e))return!0;let s=!1;for(const i of e.nodes){const e="attribute"===i.type&&i.attribute||i.value;if(e&&this.isSelectorWhitelistedChildren(e))return!0;if(e&&(c.includes(e)||this.isSelectorWhitelisted(e)))s=!0;else{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=S(i,t);break;case"tag":s=b(i,t)}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&&(g(e,"start")?(this.ignore=!0,e.remove()):g(e,"end")&&(this.ignore=!1,e.remove()))))}}exports.PurgeCSS=x,exports.default=x,exports.defaultOptions=o,exports.mergeExtractorSelectors=v,exports.setOptions=p;
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "purgecss",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "Remove unused css selectors",
|
|
5
|
-
"author": "Ffloriel
|
|
5
|
+
"author": "Ffloriel",
|
|
6
6
|
"homepage": "https://purgecss.com",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"optimize",
|
|
@@ -39,16 +39,16 @@
|
|
|
39
39
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"commander": "^
|
|
42
|
+
"commander": "^5.0.0",
|
|
43
43
|
"glob": "^7.0.0",
|
|
44
|
-
"postcss": "7.0.
|
|
44
|
+
"postcss": "7.0.28",
|
|
45
45
|
"postcss-selector-parser": "^6.0.2"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@types/glob": "^7.1.1"
|
|
48
|
+
"@types/glob": "^7.1.1",
|
|
49
|
+
"tailwindcss": "^1.2.0"
|
|
49
50
|
},
|
|
50
51
|
"bugs": {
|
|
51
52
|
"url": "https://github.com/FullHuman/purgecss/issues"
|
|
52
|
-
}
|
|
53
|
-
"gitHead": "11f76506924277ec6833e0cd7d0798676b4ac9ef"
|
|
53
|
+
}
|
|
54
54
|
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2020 Full Human
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|