postcss-discard-unused 8.0.1 → 8.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE-MIT CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) Ben Briggs <beneb.info@gmail.com> (http://beneb.info)
1
+ Copyright (c) Ben Briggs <beneb.info@gmail.com> (https://beneb.info)
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person
4
4
  obtaining a copy of this software and associated documentation
package/README.md CHANGED
@@ -120,7 +120,7 @@ See [CONTRIBUTORS.md](https://github.com/cssnano/cssnano/blob/master/CONTRIBUTOR
120
120
 
121
121
  ## License
122
122
 
123
- MIT © [Ben Briggs](http://beneb.info)
123
+ MIT © [Ben Briggs](https://beneb.info)
124
124
 
125
125
 
126
126
  [postcss]: https://github.com/postcss/postcss
package/package.json CHANGED
@@ -1,9 +1,17 @@
1
1
  {
2
2
  "name": "postcss-discard-unused",
3
- "version": "8.0.1",
3
+ "version": "8.0.3",
4
4
  "description": "Discard unused counter styles, keyframes and fonts.",
5
- "main": "src/index.js",
6
- "types": "types/index.d.ts",
5
+ "exports": {
6
+ ".": {
7
+ "types": "./types/index.d.ts",
8
+ "default": "./src/index.js"
9
+ },
10
+ "./src": "./src/index.js",
11
+ "./src/index": "./src/index.js",
12
+ "./src/index.js": "./src/index.js",
13
+ "./package.json": "./package.json"
14
+ },
7
15
  "files": [
8
16
  "LICENSE-MIT",
9
17
  "src",
@@ -22,11 +30,14 @@
22
30
  "author": {
23
31
  "name": "Ben Briggs",
24
32
  "email": "beneb.info@gmail.com",
25
- "url": "http://beneb.info"
33
+ "url": "https://beneb.info"
34
+ },
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "cssnano/cssnano"
26
38
  },
27
- "repository": "cssnano/cssnano",
28
39
  "dependencies": {
29
- "postcss-selector-parser": "^7.1.2"
40
+ "postcss-selector-parser": "^7.1.5"
30
41
  },
31
42
  "bugs": {
32
43
  "url": "https://github.com/cssnano/cssnano/issues"
@@ -35,9 +46,12 @@
35
46
  "node": "^22.11.0 || ^24.11.0 || >=26.0"
36
47
  },
37
48
  "devDependencies": {
38
- "postcss": "^8.5.15"
49
+ "postcss": "^8.5.26"
39
50
  },
40
51
  "peerDependencies": {
41
- "postcss": "^8.5.15"
52
+ "postcss": "^8.5.26"
53
+ },
54
+ "scripts": {
55
+ "test": "node --test"
42
56
  }
43
57
  }
package/src/index.js CHANGED
@@ -4,6 +4,12 @@ const selectorParser = require('postcss-selector-parser');
4
4
  const atrule = 'atrule';
5
5
  const decl = 'decl';
6
6
  const rule = 'rule';
7
+ const animationRegex = /animation/;
8
+ const listStyleRegex = /list-style|system/;
9
+ const fontRegex = /font(|-family)/;
10
+ const counterStyleRegex = /counter-style/;
11
+ const keyframesRegex = /keyframes/;
12
+
7
13
  /**
8
14
  * @param {{value: string}} arg
9
15
  * @param {(input: string) => string[]} comma
@@ -25,13 +31,13 @@ function splitValues({ value }, comma, space) {
25
31
  */
26
32
  function filterAtRule({ atRules, values }) {
27
33
  const uniqueValues = new Set(values);
28
- atRules.forEach((node) => {
34
+ for (const node of atRules) {
29
35
  const hasAtRule = uniqueValues.has(node.params);
30
36
 
31
37
  if (!hasAtRule) {
32
38
  node.remove();
33
39
  }
34
- });
40
+ }
35
41
  }
36
42
 
37
43
  /**
@@ -65,7 +71,7 @@ function hasFont(fontFamily, cache, comma) {
65
71
  return comma(fontFamily).some((font) => cache.some((c) => c.includes(font)));
66
72
  }
67
73
 
68
- /**
74
+ /**
69
75
  * fonts have slightly different logic
70
76
 
71
77
  * @param {{atRules: import('postcss').AtRule[], values: string[]}} cache
@@ -97,9 +103,149 @@ function filterFont({ atRules, values }, comma) {
97
103
  }
98
104
  }
99
105
 
106
+ /**
107
+ *
108
+ * @param {{atRules: import('postcss').AtRule[], rules: (string | true)[]}} namespaceCache
109
+ * @param {import('postcss').Rule} node
110
+ * @return {void}
111
+ */
112
+ function processAttributeSelector(namespaceCache, node) {
113
+ selectorParser((ast) => {
114
+ ast.walkAttributes(({ namespace: ns }) => {
115
+ namespaceCache.rules = namespaceCache.rules.concat(ns);
116
+ });
117
+ }).process(node.selector);
118
+ }
119
+
100
120
  /**@typedef {{fontFace?: boolean, counterStyle?: boolean, keyframes?: boolean, namespace?: boolean}} Options */
121
+
122
+ /**
123
+ * @param {import('postcss').AnyNode} node
124
+ * @param {{
125
+ * fontFace: boolean,
126
+ * counterStyle: boolean,
127
+ * keyframes: boolean,
128
+ * namespace: boolean,
129
+ * counterStyleCache: {atRules: import('postcss').AtRule[], values: string[]},
130
+ * keyframesCache: {atRules: import('postcss').AtRule[], values: string[]},
131
+ * namespaceCache: {atRules: import('postcss').AtRule[], rules: (string | true)[]},
132
+ * fontCache: {atRules: import('postcss').AtRule[], values: string[]},
133
+ * comma: (input: string) => string[],
134
+ * space: (input: string) => string[],
135
+ * }} context
136
+ * @return {void}
137
+ */
138
+ function processNode(node, context) {
139
+ if (node.type === rule && context.namespace && node.selector.includes('|')) {
140
+ processRule(context.namespaceCache, node);
141
+ return;
142
+ }
143
+
144
+ if (node.type === decl) {
145
+ processDeclaration(node, context);
146
+ return;
147
+ }
148
+
149
+ if (node.type === atrule) {
150
+ processAtRule(node, context);
151
+ }
152
+ }
153
+
154
+ /**
155
+ * @param {{atRules: import('postcss').AtRule[], rules: (string | true)[]}} namespaceCache
156
+ * @param {import('postcss').Rule} node
157
+ * @return {void}
158
+ */
159
+ function processRule(namespaceCache, node) {
160
+ if (node.selector.includes('[')) {
161
+ // Attribute selector, so we should parse further.
162
+ processAttributeSelector(namespaceCache, node);
163
+ } else {
164
+ // Use a simple split function for the namespace
165
+ namespaceCache.rules = namespaceCache.rules.concat(
166
+ node.selector.split('|')[0]
167
+ );
168
+ }
169
+ }
170
+
171
+ /**
172
+ * @param {import('postcss').Declaration} node
173
+ * @param {{
174
+ * fontFace: boolean,
175
+ * counterStyle: boolean,
176
+ * keyframes: boolean,
177
+ * namespace: boolean,
178
+ * counterStyleCache: {atRules: import('postcss').AtRule[], values: string[]},
179
+ * keyframesCache: {atRules: import('postcss').AtRule[], values: string[]},
180
+ * namespaceCache: {atRules: import('postcss').AtRule[], rules: (string | true)[]},
181
+ * fontCache: {atRules: import('postcss').AtRule[], values: string[]},
182
+ * comma: (input: string) => string[],
183
+ * space: (input: string) => string[],
184
+ * }} context
185
+ * @return {void}
186
+ */
187
+ function processDeclaration(node, context) {
188
+ const { prop } = node;
189
+ if (context.counterStyle && listStyleRegex.test(prop)) {
190
+ context.counterStyleCache.values = context.counterStyleCache.values.concat(
191
+ splitValues(node, context.comma, context.space)
192
+ );
193
+ }
194
+
195
+ if (
196
+ context.fontFace &&
197
+ node.parent !== undefined &&
198
+ node.parent.type === rule &&
199
+ fontRegex.test(prop)
200
+ ) {
201
+ context.fontCache.values = context.fontCache.values.concat(
202
+ context.comma(node.value.toLowerCase())
203
+ );
204
+ }
205
+
206
+ if (context.keyframes && animationRegex.test(prop)) {
207
+ context.keyframesCache.values = context.keyframesCache.values.concat(
208
+ splitValues(node, context.comma, context.space)
209
+ );
210
+ }
211
+ }
212
+
213
+ /**
214
+ * @param {import('postcss').AtRule} node
215
+ * @param {{
216
+ * fontFace: boolean,
217
+ * counterStyle: boolean,
218
+ * keyframes: boolean,
219
+ * namespace: boolean,
220
+ * counterStyleCache: {atRules: import('postcss').AtRule[], values: string[]},
221
+ * keyframesCache: {atRules: import('postcss').AtRule[], values: string[]},
222
+ * namespaceCache: {atRules: import('postcss').AtRule[], rules: (string | true)[]},
223
+ * fontCache: {atRules: import('postcss').AtRule[], values: string[]},
224
+ * comma: (input: string) => string[],
225
+ * space: (input: string) => string[],
226
+ * }} context
227
+ * @return {void}
228
+ */
229
+ function processAtRule(node, context) {
230
+ const { name } = node;
231
+ if (context.counterStyle && counterStyleRegex.test(name)) {
232
+ context.counterStyleCache.atRules.push(node);
233
+ }
234
+
235
+ if (context.fontFace && name === 'font-face' && node.nodes) {
236
+ context.fontCache.atRules.push(node);
237
+ }
238
+
239
+ if (context.keyframes && keyframesRegex.test(name)) {
240
+ context.keyframesCache.atRules.push(node);
241
+ }
242
+
243
+ if (context.namespace && name === 'namespace') {
244
+ context.namespaceCache.atRules.push(node);
245
+ }
246
+ }
247
+
101
248
  /**
102
- * @type {import('postcss').PluginCreator<Options>}
103
249
  * @param {Options} opts
104
250
  * @return {import('postcss').Plugin}
105
251
  */
@@ -129,82 +275,40 @@ function pluginCreator(opts) {
129
275
  const fontCache = { atRules: [], values: [] };
130
276
 
131
277
  return {
278
+ /**
279
+ * @param {import('postcss').Root} css
280
+ * @param {import('postcss').Helpers} helpers
281
+ */
132
282
  OnceExit(css, { list }) {
133
283
  const { comma, space } = list;
284
+ const context = {
285
+ fontFace,
286
+ counterStyle,
287
+ keyframes,
288
+ namespace,
289
+ counterStyleCache,
290
+ keyframesCache,
291
+ namespaceCache,
292
+ fontCache,
293
+ comma,
294
+ space,
295
+ };
134
296
  css.walk((node) => {
135
- const { type } = node;
136
-
137
- if (type === rule && namespace && node.selector.includes('|')) {
138
- if (node.selector.includes('[')) {
139
- // Attribute selector, so we should parse further.
140
- selectorParser((ast) => {
141
- ast.walkAttributes(({ namespace: ns }) => {
142
- namespaceCache.rules = namespaceCache.rules.concat(ns);
143
- });
144
- }).process(node.selector);
145
- } else {
146
- // Use a simple split function for the namespace
147
- namespaceCache.rules = namespaceCache.rules.concat(
148
- node.selector.split('|')[0]
149
- );
150
- }
151
- return;
152
- }
153
-
154
- if (type === decl) {
155
- const { prop } = node;
156
- if (counterStyle && /list-style|system/.test(prop)) {
157
- counterStyleCache.values = counterStyleCache.values.concat(
158
- splitValues(node, comma, space)
159
- );
160
- }
161
-
162
- if (
163
- fontFace &&
164
- node.parent !== undefined &&
165
- node.parent.type === rule &&
166
- /font(|-family)/.test(prop)
167
- ) {
168
- fontCache.values = fontCache.values.concat(
169
- comma(node.value.toLowerCase())
170
- );
171
- }
172
-
173
- if (keyframes && /animation/.test(prop)) {
174
- keyframesCache.values = keyframesCache.values.concat(
175
- splitValues(node, comma, space)
176
- );
177
- }
178
-
179
- return;
180
- }
181
-
182
- if (type === atrule) {
183
- const { name } = node;
184
- if (counterStyle && /counter-style/.test(name)) {
185
- counterStyleCache.atRules.push(node);
186
- }
187
-
188
- if (fontFace && name === 'font-face' && node.nodes) {
189
- fontCache.atRules.push(node);
190
- }
191
-
192
- if (keyframes && /keyframes/.test(name)) {
193
- keyframesCache.atRules.push(node);
194
- }
195
-
196
- if (namespace && name === 'namespace') {
197
- namespaceCache.atRules.push(node);
198
- }
199
-
200
- return;
201
- }
297
+ processNode(node, context);
202
298
  });
203
299
 
204
- counterStyle && filterAtRule(counterStyleCache);
205
- fontFace && filterFont(fontCache, comma);
206
- keyframes && filterAtRule(keyframesCache);
207
- namespace && filterNamespace(namespaceCache);
300
+ if (counterStyle) {
301
+ filterAtRule(counterStyleCache);
302
+ }
303
+ if (fontFace) {
304
+ filterFont(fontCache, comma);
305
+ }
306
+ if (keyframes) {
307
+ filterAtRule(keyframesCache);
308
+ }
309
+ if (namespace) {
310
+ filterNamespace(namespaceCache);
311
+ }
208
312
  },
209
313
  };
210
314
  },
@@ -212,4 +316,6 @@ function pluginCreator(opts) {
212
316
  }
213
317
 
214
318
  pluginCreator.postcss = true;
215
- module.exports = pluginCreator;
319
+ module.exports = /** @type {import('postcss').PluginCreator<Options>}*/ (
320
+ pluginCreator
321
+ );
package/types/index.d.ts CHANGED
@@ -1,16 +1,6 @@
1
- export = pluginCreator;
2
- /**@typedef {{fontFace?: boolean, counterStyle?: boolean, keyframes?: boolean, namespace?: boolean}} Options */
3
- /**
4
- * @type {import('postcss').PluginCreator<Options>}
5
- * @param {Options} opts
6
- * @return {import('postcss').Plugin}
7
- */
8
- declare function pluginCreator(opts: Options): import("postcss").Plugin;
9
- declare namespace pluginCreator {
10
- export { postcss, Options };
11
- }
12
- declare var postcss: true;
13
- type Options = {
1
+ declare const _exports: import("postcss").PluginCreator<Options>;
2
+ export = _exports;
3
+ export type Options = {
14
4
  fontFace?: boolean;
15
5
  counterStyle?: boolean;
16
6
  keyframes?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":";AAmGA,+GAA+G;AAC/G;;;;GAIG;AACH,qCAHW,OAAO,GACN,OAAO,SAAS,EAAE,MAAM,CA4GnC;;;;;eAhHY;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":";;AAuHG,YAAkG,OAAO,GAA/F;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAC,CAAS"}