postcss-minify-gradients 8.0.1 → 8.0.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/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.2",
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.2"
29
40
  },
30
41
  "bugs": {
31
42
  "url": "https://github.com/cssnano/cssnano/issues"
@@ -34,9 +45,9 @@
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.25"
38
49
  },
39
50
  "peerDependencies": {
40
- "postcss": "^8.5.15"
51
+ "postcss": "^8.5.25"
41
52
  }
42
53
  }
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,34 @@ 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
  }
208
245
  })
209
246
  .toString();
210
247
  }
211
248
  /**
212
- * @type {import('postcss').PluginCreator<void>}
213
249
  * @return {import('postcss').Plugin}
214
250
  */
215
251
  function pluginCreator() {
216
252
  return {
217
253
  postcssPlugin: 'postcss-minify-gradients',
254
+ /**
255
+ * @param {import('postcss').Root} css
256
+ */
218
257
  OnceExit(css) {
219
258
  css.walkDecls(optimise);
220
259
  },
@@ -222,4 +261,6 @@ function pluginCreator() {
222
261
  }
223
262
 
224
263
  pluginCreator.postcss = true;
225
- module.exports = pluginCreator;
264
+ module.exports = /** @type {import('postcss').PluginCreator<void>}*/ (
265
+ pluginCreator
266
+ );
@@ -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"}