postcss-minify-gradients 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
@@ -48,6 +48,6 @@ See [CONTRIBUTORS.md](https://github.com/cssnano/cssnano/blob/master/CONTRIBUTOR
48
48
 
49
49
  ## License
50
50
 
51
- MIT © [Ben Briggs](http://beneb.info)
51
+ MIT © [Ben Briggs](https://beneb.info)
52
52
 
53
53
  [postcss]: https://github.com/postcss/postcss
package/package.json CHANGED
@@ -1,9 +1,17 @@
1
1
  {
2
2
  "name": "postcss-minify-gradients",
3
- "version": "8.0.1",
3
+ "version": "8.0.3",
4
4
  "description": "Minify gradient parameters with PostCSS.",
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/*": "./src/*.js",
12
+ "./src/*.js": "./src/*.js",
13
+ "./package.json": "./package.json"
14
+ },
7
15
  "files": [
8
16
  "LICENSE-MIT",
9
17
  "src",
@@ -19,13 +27,16 @@
19
27
  "author": {
20
28
  "name": "Ben Briggs",
21
29
  "email": "beneb.info@gmail.com",
22
- "url": "http://beneb.info"
30
+ "url": "https://beneb.info"
31
+ },
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "cssnano/cssnano"
23
35
  },
24
- "repository": "cssnano/cssnano",
25
36
  "dependencies": {
26
- "@colordx/core": "^5.4.3",
37
+ "@colordx/core": "^5.5.0",
27
38
  "postcss-value-parser": "^4.2.0",
28
- "cssnano-utils": "^6.0.1"
39
+ "cssnano-utils": "^6.0.3"
29
40
  },
30
41
  "bugs": {
31
42
  "url": "https://github.com/cssnano/cssnano/issues"
@@ -34,9 +45,12 @@
34
45
  "node": "^22.11.0 || ^24.11.0 || >=26.0"
35
46
  },
36
47
  "devDependencies": {
37
- "postcss": "^8.5.15"
48
+ "postcss": "^8.5.26"
38
49
  },
39
50
  "peerDependencies": {
40
- "postcss": "^8.5.15"
51
+ "postcss": "^8.5.26"
52
+ },
53
+ "scripts": {
54
+ "test": "node --test"
41
55
  }
42
56
  }
package/src/index.js CHANGED
@@ -3,17 +3,19 @@ const valueParser = require('postcss-value-parser');
3
3
  const { getArguments } = require('cssnano-utils');
4
4
  const isColorStop = require('./isColorStop.js');
5
5
 
6
- const angles = {
7
- top: '0deg',
8
- right: '90deg',
9
- bottom: '180deg',
10
- left: '270deg',
11
- };
6
+ const directionsToAngles = new Map([
7
+ ['top', '0deg'],
8
+ ['right', '90deg'],
9
+ ['bottom', '180deg'],
10
+ ['left', '270deg'],
11
+ ]);
12
12
 
13
13
  /**
14
+ * Returns whether b is less than a.
15
+ *
14
16
  * @param {valueParser.Dimension} a
15
17
  * @param {valueParser.Dimension} b
16
- * @return {boolean}
18
+ * @returns {boolean}
17
19
  */
18
20
  function isLessThan(a, b) {
19
21
  return (
@@ -21,6 +23,174 @@ function isLessThan(a, b) {
21
23
  parseFloat(a.number) >= parseFloat(b.number)
22
24
  );
23
25
  }
26
+
27
+ /**
28
+ * Shortens a direction like `to left top` into an angle.
29
+ *
30
+ * @param {import('postcss-value-parser').FunctionNode} node
31
+ * @returns {void}
32
+ */
33
+ function shortenDirection(node) {
34
+ node.nodes = node.nodes.slice(2);
35
+ node.nodes[0].value = /** @type {string} */ (
36
+ directionsToAngles.get(node.nodes[0].value.toLowerCase())
37
+ );
38
+ }
39
+
40
+ /**
41
+ * Optimises a linear gradient.
42
+ *
43
+ * @param {import('postcss-value-parser').FunctionNode} node
44
+ * @returns {false}
45
+ */
46
+ function optimizeLinearGradient(node) {
47
+ const args = getArguments(node);
48
+ if (node.nodes[0].value.toLowerCase() === 'to' && args[0].length === 3) {
49
+ shortenDirection(node);
50
+ }
51
+ /** @type {valueParser.Dimension | false | undefined} */
52
+ let previousStop = undefined;
53
+
54
+ for (const [index, arg] of args.entries()) {
55
+ /* Check whether the stop contains a position */
56
+ if (arg.length !== 3) {
57
+ continue;
58
+ }
59
+
60
+ const isFinalStop = index === args.length - 1;
61
+ const thisStop = valueParser.unit(arg[2].value);
62
+
63
+ if (previousStop === undefined) {
64
+ previousStop = thisStop;
65
+
66
+ if (
67
+ !isFinalStop &&
68
+ previousStop &&
69
+ args.length < 4 &&
70
+ previousStop.number === '0' &&
71
+ previousStop.unit.toLowerCase() !== 'deg'
72
+ ) {
73
+ arg[1].value = arg[2].value = '';
74
+ }
75
+
76
+ continue;
77
+ }
78
+
79
+ if (previousStop && thisStop && isLessThan(previousStop, thisStop)) {
80
+ arg[2].value = '0';
81
+ }
82
+
83
+ previousStop = thisStop;
84
+
85
+ if (isFinalStop && arg[2].value === '100%') {
86
+ arg[1].value = arg[2].value = '';
87
+ }
88
+ }
89
+
90
+ return false;
91
+ }
92
+
93
+ /**
94
+ * Optimises a radial gradient.
95
+ *
96
+ * @param {import('postcss-value-parser').ParsedValue | import('postcss-value-parser').FunctionNode} node
97
+ * @returns {false}
98
+ */
99
+ function optimizeRadialGradient(node) {
100
+ const args = getArguments(node);
101
+ /** @type {valueParser.Dimension | false | undefined} */
102
+ let previousStop = undefined;
103
+
104
+ const hasAt = args[0].find((n) => n.value.toLowerCase() === 'at');
105
+
106
+ for (const [index, arg] of args.entries()) {
107
+ if (!arg[2] || (!index && hasAt)) {
108
+ continue;
109
+ }
110
+
111
+ const thisStop = valueParser.unit(arg[2].value);
112
+
113
+ if (!previousStop) {
114
+ previousStop = thisStop;
115
+
116
+ continue;
117
+ }
118
+
119
+ if (previousStop && thisStop && isLessThan(previousStop, thisStop)) {
120
+ arg[2].value = '0';
121
+ }
122
+
123
+ previousStop = thisStop;
124
+ }
125
+
126
+ return false;
127
+ }
128
+
129
+ /**
130
+ * Optimises a radial gradient.
131
+ *
132
+ * @param {import('postcss-value-parser').ParsedValue | import('postcss-value-parser').FunctionNode} node
133
+ * @returns {false}
134
+ */
135
+ function optimizeWebkitRadialGradient(node) {
136
+ const args = getArguments(node);
137
+ /** @type {valueParser.Dimension | false | undefined} */
138
+ let previousStop = undefined;
139
+
140
+ for (const arg of args) {
141
+ let color;
142
+ let stop;
143
+
144
+ if (arg[2] !== undefined) {
145
+ if (arg[0].type === 'function') {
146
+ color = `${arg[0].value}(${valueParser.stringify(arg[0].nodes)})`;
147
+ } else {
148
+ color = arg[0].value;
149
+ }
150
+
151
+ if (arg[2].type === 'function') {
152
+ stop = `${arg[2].value}(${valueParser.stringify(arg[2].nodes)})`;
153
+ } else {
154
+ stop = arg[2].value;
155
+ }
156
+ } else {
157
+ if (arg[0].type === 'function') {
158
+ // eslint-disable-next-line no-useless-assignment
159
+ color = `${arg[0].value}(${valueParser.stringify(arg[0].nodes)})`;
160
+ }
161
+
162
+ color = arg[0].value;
163
+ }
164
+
165
+ color = color.toLowerCase();
166
+
167
+ const colorStop =
168
+ stop !== undefined
169
+ ? isColorStop(color, stop.toLowerCase())
170
+ : isColorStop(color);
171
+
172
+ if (!colorStop || !arg[2]) {
173
+ continue;
174
+ }
175
+
176
+ const thisStop = valueParser.unit(arg[2].value);
177
+
178
+ if (!previousStop) {
179
+ previousStop = thisStop;
180
+
181
+ continue;
182
+ }
183
+
184
+ if (previousStop && thisStop && isLessThan(previousStop, thisStop)) {
185
+ arg[2].value = '0';
186
+ }
187
+
188
+ previousStop = thisStop;
189
+ }
190
+
191
+ return false;
192
+ }
193
+
24
194
  /**
25
195
  * @param {import('postcss').Declaration} decl
26
196
  * @return {void}
@@ -56,165 +226,35 @@ function optimise(decl) {
56
226
  lowerCasedValue === '-webkit-linear-gradient' ||
57
227
  lowerCasedValue === '-webkit-repeating-linear-gradient'
58
228
  ) {
59
- let args = getArguments(node);
60
-
61
- if (
62
- node.nodes[0].value.toLowerCase() === 'to' &&
63
- args[0].length === 3
64
- ) {
65
- node.nodes = node.nodes.slice(2);
66
- node.nodes[0].value =
67
- angles[
68
- /** @type {'top'|'right'|'bottom'|'left'}*/ (
69
- node.nodes[0].value.toLowerCase()
70
- )
71
- ];
72
- }
73
-
74
- /** @type {valueParser.Dimension | false} */
75
- let lastStop;
76
-
77
- args.forEach((arg, index) => {
78
- if (arg.length !== 3) {
79
- return;
80
- }
81
-
82
- let isFinalStop = index === args.length - 1;
83
- let thisStop = valueParser.unit(arg[2].value);
84
-
85
- if (lastStop === undefined) {
86
- lastStop = thisStop;
87
-
88
- if (
89
- !isFinalStop &&
90
- lastStop &&
91
- lastStop.number === '0' &&
92
- lastStop.unit.toLowerCase() !== 'deg'
93
- ) {
94
- arg[1].value = arg[2].value = '';
95
- }
96
-
97
- return;
98
- }
99
-
100
- if (lastStop && thisStop && isLessThan(lastStop, thisStop)) {
101
- arg[2].value = '0';
102
- }
103
-
104
- lastStop = thisStop;
105
-
106
- if (isFinalStop && arg[2].value === '100%') {
107
- arg[1].value = arg[2].value = '';
108
- }
109
- });
110
-
111
- return false;
229
+ return optimizeLinearGradient(node);
112
230
  }
113
231
 
114
232
  if (
115
233
  lowerCasedValue === 'radial-gradient' ||
116
234
  lowerCasedValue === 'repeating-radial-gradient'
117
235
  ) {
118
- let args = getArguments(node);
119
- /** @type {valueParser.Dimension | false} */
120
- let lastStop;
121
-
122
- const hasAt = args[0].find((n) => n.value.toLowerCase() === 'at');
123
-
124
- args.forEach((arg, index) => {
125
- if (!arg[2] || (!index && hasAt)) {
126
- return;
127
- }
128
-
129
- let thisStop = valueParser.unit(arg[2].value);
130
-
131
- if (!lastStop) {
132
- lastStop = thisStop;
133
-
134
- return;
135
- }
136
-
137
- if (lastStop && thisStop && isLessThan(lastStop, thisStop)) {
138
- arg[2].value = '0';
139
- }
140
-
141
- lastStop = thisStop;
142
- });
143
-
144
- return false;
236
+ return optimizeRadialGradient(node);
145
237
  }
146
238
 
147
239
  if (
148
240
  lowerCasedValue === '-webkit-radial-gradient' ||
149
241
  lowerCasedValue === '-webkit-repeating-radial-gradient'
150
242
  ) {
151
- let args = getArguments(node);
152
- /** @type {valueParser.Dimension | false} */
153
- let lastStop;
154
-
155
- args.forEach((arg) => {
156
- let color;
157
- let stop;
158
-
159
- if (arg[2] !== undefined) {
160
- if (arg[0].type === 'function') {
161
- color = `${arg[0].value}(${valueParser.stringify(arg[0].nodes)})`;
162
- } else {
163
- color = arg[0].value;
164
- }
165
-
166
- if (arg[2].type === 'function') {
167
- stop = `${arg[2].value}(${valueParser.stringify(arg[2].nodes)})`;
168
- } else {
169
- stop = arg[2].value;
170
- }
171
- } else {
172
- if (arg[0].type === 'function') {
173
- // eslint-disable-next-line no-useless-assignment
174
- color = `${arg[0].value}(${valueParser.stringify(arg[0].nodes)})`;
175
- }
176
-
177
- color = arg[0].value;
178
- }
179
-
180
- color = color.toLowerCase();
181
-
182
- const colorStop =
183
- stop !== undefined
184
- ? isColorStop(color, stop.toLowerCase())
185
- : isColorStop(color);
186
-
187
- if (!colorStop || !arg[2]) {
188
- return;
189
- }
190
-
191
- let thisStop = valueParser.unit(arg[2].value);
192
-
193
- if (!lastStop) {
194
- lastStop = thisStop;
195
-
196
- return;
197
- }
198
-
199
- if (lastStop && thisStop && isLessThan(lastStop, thisStop)) {
200
- arg[2].value = '0';
201
- }
202
-
203
- lastStop = thisStop;
204
- });
205
-
206
- return false;
243
+ return optimizeWebkitRadialGradient(node);
207
244
  }
245
+ return false;
208
246
  })
209
247
  .toString();
210
248
  }
211
249
  /**
212
- * @type {import('postcss').PluginCreator<void>}
213
250
  * @return {import('postcss').Plugin}
214
251
  */
215
252
  function pluginCreator() {
216
253
  return {
217
254
  postcssPlugin: 'postcss-minify-gradients',
255
+ /**
256
+ * @param {import('postcss').Root} css
257
+ */
218
258
  OnceExit(css) {
219
259
  css.walkDecls(optimise);
220
260
  },
@@ -222,4 +262,6 @@ function pluginCreator() {
222
262
  }
223
263
 
224
264
  pluginCreator.postcss = true;
225
- module.exports = pluginCreator;
265
+ module.exports = /** @type {import('postcss').PluginCreator<void>}*/ (
266
+ pluginCreator
267
+ );
@@ -6,7 +6,7 @@ const namesPlugin = require('@colordx/core/plugins/names');
6
6
 
7
7
  extend([/** @type {any} */ (hwbPlugin), /** @type {any} */ (namesPlugin)]);
8
8
 
9
- /* Code derived from https://github.com/pigcan/is-color-stop */
9
+ /* Code derived from https://www.npmjs.com/package/is-color-stop Licensed under MIT license */
10
10
 
11
11
  const lengthUnits = new Set([
12
12
  'PX',
@@ -26,6 +26,8 @@ const lengthUnits = new Set([
26
26
  '%',
27
27
  ]);
28
28
 
29
+ const colorStopRegex = /^calc\(\S+\)$/g;
30
+
29
31
  /**
30
32
  * @param {string} input
31
33
  * @return {boolean}
@@ -39,17 +41,17 @@ function isCSSLengthUnit(input) {
39
41
  */
40
42
  function isStop(str) {
41
43
  if (str) {
42
- let stop = false;
44
+ let isColorStop = false;
43
45
  const node = unit(str);
44
46
  if (node) {
45
47
  const number = Number(node.number);
46
48
  if (number === 0 || (!isNaN(number) && isCSSLengthUnit(node.unit))) {
47
- stop = true;
49
+ isColorStop = true;
48
50
  }
49
51
  } else {
50
- stop = /^calc\(\S+\)$/g.test(str);
52
+ isColorStop = colorStopRegex.test(str);
51
53
  }
52
- return stop;
54
+ return isColorStop;
53
55
  }
54
56
  return true;
55
57
  }
package/types/index.d.ts CHANGED
@@ -1,10 +1,3 @@
1
- export = pluginCreator;
2
- /**
3
- * @type {import('postcss').PluginCreator<void>}
4
- * @return {import('postcss').Plugin}
5
- */
6
- declare function pluginCreator(): import("postcss").Plugin;
7
- declare namespace pluginCreator {
8
- let postcss: true;
9
- }
1
+ declare const _exports: import("postcss").PluginCreator<void>;
2
+ export = _exports;
10
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":";AAkNA;;;GAGG;AACH,kCAFY,OAAO,SAAS,EAAE,MAAM,CASnC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":""}
@@ -1,3 +1,8 @@
1
- declare function _exports(color: string, stop?: string): boolean;
2
- export = _exports;
1
+ export = isColorStop;
2
+ /**
3
+ * @param {string} color
4
+ * @param {string} [stop]
5
+ * @return {boolean}
6
+ */
7
+ declare function isColorStop(color: string, stop?: string): boolean;
3
8
  //# sourceMappingURL=isColorStop.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"isColorStop.d.ts","sourceRoot":"","sources":["../src/isColorStop.js"],"names":[],"mappings":"AA4DiB,iCAJN,MAAM,SACN,MAAM,GACL,OAAO,CAIlB"}
1
+ {"version":3,"file":"isColorStop.d.ts","sourceRoot":"","sources":["../src/isColorStop.js"],"names":[],"mappings":";AAyDA;;;;GAIG;6BACmC,KAAK,EAJhC,MAIgC,EAAE,IAAI,AAH9C,CACA,EADQ,MAGsC,GAFrC,OAAO"}