1 | 'use strict';
|
2 | const browserslist = require('browserslist');
|
3 | const valueParser = require('postcss-value-parser');
|
4 | const { getArguments } = require('cssnano-utils');
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 | function gcd(a, b) {
|
15 | return b ? gcd(b, a % b) : a;
|
16 | }
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 | function aspectRatio(a, b) {
|
24 | const divisor = gcd(a, b);
|
25 |
|
26 | return [a / divisor, b / divisor];
|
27 | }
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 | function split(args) {
|
34 | return args.map((arg) => valueParser.stringify(arg)).join('');
|
35 | }
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 | function removeNode(node) {
|
42 | node.value = '';
|
43 | node.type = 'word';
|
44 | }
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 | function sortAndDedupe(items) {
|
51 | const a = [...new Set(items)];
|
52 | a.sort();
|
53 | return a.join();
|
54 | }
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 | function transform(legacy, rule) {
|
62 | const ruleName = rule.name.toLowerCase();
|
63 |
|
64 |
|
65 | if (!rule.params || !['media', 'supports'].includes(ruleName)) {
|
66 | return;
|
67 | }
|
68 |
|
69 | const params = valueParser(rule.params);
|
70 |
|
71 | params.walk((node, index) => {
|
72 | if (node.type === 'div') {
|
73 | node.before = node.after = '';
|
74 | } else if (node.type === 'function') {
|
75 | node.before = '';
|
76 | if (
|
77 | node.nodes[0] &&
|
78 | node.nodes[0].type === 'word' &&
|
79 | node.nodes[0].value.startsWith('--') &&
|
80 | node.nodes[2] === undefined
|
81 | ) {
|
82 | node.after = ' ';
|
83 | } else {
|
84 | node.after = '';
|
85 | }
|
86 | if (
|
87 | node.nodes[4] &&
|
88 | node.nodes[0].value.toLowerCase().indexOf('-aspect-ratio') === 3
|
89 | ) {
|
90 | const [a, b] = aspectRatio(
|
91 | Number(node.nodes[2].value),
|
92 | Number(node.nodes[4].value)
|
93 | );
|
94 |
|
95 | node.nodes[2].value = a.toString();
|
96 | node.nodes[4].value = b.toString();
|
97 | }
|
98 | } else if (node.type === 'space') {
|
99 | node.value = ' ';
|
100 | } else {
|
101 | const prevWord = params.nodes[index - 2];
|
102 |
|
103 | if (
|
104 | node.value.toLowerCase() === 'all' &&
|
105 | rule.name.toLowerCase() === 'media' &&
|
106 | !prevWord
|
107 | ) {
|
108 | const nextWord = params.nodes[index + 2];
|
109 |
|
110 | if (!legacy || nextWord) {
|
111 | removeNode(node);
|
112 | }
|
113 |
|
114 | if (nextWord && nextWord.value.toLowerCase() === 'and') {
|
115 | const nextSpace = params.nodes[index + 1];
|
116 | const secondSpace = params.nodes[index + 3];
|
117 |
|
118 | removeNode(nextWord);
|
119 | removeNode(nextSpace);
|
120 | removeNode(secondSpace);
|
121 | }
|
122 | }
|
123 | }
|
124 | }, true);
|
125 |
|
126 | rule.params = sortAndDedupe(getArguments(params).map(split));
|
127 |
|
128 | if (!rule.params.length) {
|
129 | rule.raws.afterName = '';
|
130 | }
|
131 | }
|
132 |
|
133 | const allBugBrowers = new Set(['ie 10', 'ie 11']);
|
134 |
|
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 | function pluginCreator(options = {}) {
|
141 | const browsers = browserslist(null, {
|
142 | stats: options.stats,
|
143 | path: __dirname,
|
144 | env: options.env,
|
145 | });
|
146 |
|
147 | const hasAllBug = browsers.some((browser) => allBugBrowers.has(browser));
|
148 | return {
|
149 | postcssPlugin: 'postcss-minify-params',
|
150 |
|
151 | OnceExit(css) {
|
152 | css.walkAtRules((rule) => transform(hasAllBug, rule));
|
153 | },
|
154 | };
|
155 | }
|
156 |
|
157 | pluginCreator.postcss = true;
|
158 | module.exports = pluginCreator;
|