postcss-discard-unused 8.0.2 → 8.0.4

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.
Files changed (2) hide show
  1. package/package.json +8 -5
  2. package/src/index.js +144 -65
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "postcss-discard-unused",
3
- "version": "8.0.2",
3
+ "version": "8.0.4",
4
4
  "description": "Discard unused counter styles, keyframes and fonts.",
5
5
  "exports": {
6
6
  ".": {
@@ -34,10 +34,10 @@
34
34
  },
35
35
  "repository": {
36
36
  "type": "git",
37
- "url": "cssnano/cssnano"
37
+ "url": "git+https://github.com/cssnano/cssnano.git"
38
38
  },
39
39
  "dependencies": {
40
- "postcss-selector-parser": "^7.1.4"
40
+ "postcss-selector-parser": "^7.1.5"
41
41
  },
42
42
  "bugs": {
43
43
  "url": "https://github.com/cssnano/cssnano/issues"
@@ -46,9 +46,12 @@
46
46
  "node": "^22.11.0 || ^24.11.0 || >=26.0"
47
47
  },
48
48
  "devDependencies": {
49
- "postcss": "^8.5.25"
49
+ "postcss": "^8.5.26"
50
50
  },
51
51
  "peerDependencies": {
52
- "postcss": "^8.5.25"
52
+ "postcss": "^8.5.26"
53
+ },
54
+ "scripts": {
55
+ "test": "node --test"
53
56
  }
54
57
  }
package/src/index.js CHANGED
@@ -31,13 +31,13 @@ function splitValues({ value }, comma, space) {
31
31
  */
32
32
  function filterAtRule({ atRules, values }) {
33
33
  const uniqueValues = new Set(values);
34
- atRules.forEach((node) => {
34
+ for (const node of atRules) {
35
35
  const hasAtRule = uniqueValues.has(node.params);
36
36
 
37
37
  if (!hasAtRule) {
38
38
  node.remove();
39
39
  }
40
- });
40
+ }
41
41
  }
42
42
 
43
43
  /**
@@ -79,7 +79,7 @@ function hasFont(fontFamily, cache, comma) {
79
79
  * @return {void}
80
80
  */
81
81
  function filterFont({ atRules, values }, comma) {
82
- values = [...new Set(values)];
82
+ const uniqueValues = [...new Set(values)];
83
83
  for (const r of atRules) {
84
84
  if (r.nodes !== undefined) {
85
85
  /** @type {import('postcss').Declaration[]} */
@@ -95,7 +95,7 @@ function filterFont({ atRules, values }, comma) {
95
95
  }
96
96
 
97
97
  for (const family of families) {
98
- if (!hasFont(family.value.toLowerCase(), values, comma)) {
98
+ if (!hasFont(family.value.toLowerCase(), uniqueValues, comma)) {
99
99
  r.remove();
100
100
  }
101
101
  }
@@ -118,6 +118,133 @@ function processAttributeSelector(namespaceCache, node) {
118
118
  }
119
119
 
120
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
+
121
248
  /**
122
249
  * @param {Options} opts
123
250
  * @return {import('postcss').Plugin}
@@ -154,68 +281,20 @@ function pluginCreator(opts) {
154
281
  */
155
282
  OnceExit(css, { list }) {
156
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
+ };
157
296
  css.walk((node) => {
158
- const { type } = node;
159
-
160
- if (type === rule && namespace && node.selector.includes('|')) {
161
- if (node.selector.includes('[')) {
162
- // Attribute selector, so we should parse further.
163
- processAttributeSelector(namespaceCache, node);
164
- } else {
165
- // Use a simple split function for the namespace
166
- namespaceCache.rules = namespaceCache.rules.concat(
167
- node.selector.split('|')[0]
168
- );
169
- }
170
- return;
171
- }
172
-
173
- if (type === decl) {
174
- const { prop } = node;
175
- if (counterStyle && listStyleRegex.test(prop)) {
176
- counterStyleCache.values = counterStyleCache.values.concat(
177
- splitValues(node, comma, space)
178
- );
179
- }
180
-
181
- if (
182
- fontFace &&
183
- node.parent !== undefined &&
184
- node.parent.type === rule &&
185
- fontRegex.test(prop)
186
- ) {
187
- fontCache.values = fontCache.values.concat(
188
- comma(node.value.toLowerCase())
189
- );
190
- }
191
-
192
- if (keyframes && animationRegex.test(prop)) {
193
- keyframesCache.values = keyframesCache.values.concat(
194
- splitValues(node, comma, space)
195
- );
196
- }
197
-
198
- return;
199
- }
200
-
201
- if (type === atrule) {
202
- const { name } = node;
203
- if (counterStyle && counterStyleRegex.test(name)) {
204
- counterStyleCache.atRules.push(node);
205
- }
206
-
207
- if (fontFace && name === 'font-face' && node.nodes) {
208
- fontCache.atRules.push(node);
209
- }
210
-
211
- if (keyframes && keyframesRegex.test(name)) {
212
- keyframesCache.atRules.push(node);
213
- }
214
-
215
- if (namespace && name === 'namespace') {
216
- namespaceCache.atRules.push(node);
217
- }
218
- }
297
+ processNode(node, context);
219
298
  });
220
299
 
221
300
  if (counterStyle) {