postcss-convert-values 9.0.2 → 9.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.
- package/package.json +4 -3
- package/src/index.js +24 -219
- package/src/lib/computeBrowsersToSupport.js +1 -3
- package/src/lib/convert.js +93 -30
- package/src/lib/parse-syntax.js +234 -0
- package/src/lib/transform.js +529 -0
- package/types/index.d.ts +2 -5
- package/types/index.d.ts.map +1 -1
- package/types/lib/computeBrowsersToSupport.d.ts.map +1 -1
- package/types/lib/convert.d.ts +21 -0
- package/types/lib/convert.d.ts.map +1 -1
- package/types/lib/parse-syntax.d.ts +3 -0
- package/types/lib/parse-syntax.d.ts.map +1 -0
- package/types/lib/transform.d.ts +20 -0
- package/types/lib/transform.d.ts.map +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "postcss-convert-values",
|
|
3
|
-
"version": "9.0.
|
|
3
|
+
"version": "9.0.4",
|
|
4
4
|
"description": "Convert values with PostCSS (e.g. ms -> s)",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"url": "git+https://github.com/cssnano/cssnano.git"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"browserslist": "^4.
|
|
44
|
-
"
|
|
43
|
+
"browserslist": "^4.29.1",
|
|
44
|
+
"cssnano-utils": "^8.0.0"
|
|
45
45
|
},
|
|
46
46
|
"bugs": {
|
|
47
47
|
"url": "https://github.com/cssnano/cssnano/issues"
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
},
|
|
58
58
|
"type": "module",
|
|
59
59
|
"scripts": {
|
|
60
|
+
"fuzz": "node ./script/fuzz.js",
|
|
60
61
|
"test": "node --test"
|
|
61
62
|
}
|
|
62
63
|
}
|
package/src/index.js
CHANGED
|
@@ -1,212 +1,8 @@
|
|
|
1
|
-
import valueParser from 'postcss-value-parser';
|
|
2
1
|
import getBrowsersList from '#getBrowsersList';
|
|
3
|
-
import
|
|
2
|
+
import transform from './lib/transform.js';
|
|
4
3
|
|
|
5
4
|
/** @import browserslist from 'browserslist' */
|
|
6
|
-
|
|
7
|
-
const LENGTH_UNITS = new Set([
|
|
8
|
-
'em',
|
|
9
|
-
'ex',
|
|
10
|
-
'ch',
|
|
11
|
-
'rem',
|
|
12
|
-
'vw',
|
|
13
|
-
'vh',
|
|
14
|
-
'vmin',
|
|
15
|
-
'vmax',
|
|
16
|
-
'cm',
|
|
17
|
-
'mm',
|
|
18
|
-
'q',
|
|
19
|
-
'in',
|
|
20
|
-
'pt',
|
|
21
|
-
'pc',
|
|
22
|
-
'px',
|
|
23
|
-
]);
|
|
24
|
-
|
|
25
|
-
// These properties only accept percentages, so no point in trying to transform
|
|
26
|
-
const notALength = new Set([
|
|
27
|
-
'descent-override',
|
|
28
|
-
'ascent-override',
|
|
29
|
-
'font-stretch',
|
|
30
|
-
'size-adjust',
|
|
31
|
-
'line-gap-override',
|
|
32
|
-
]);
|
|
33
|
-
|
|
34
|
-
// Can't change the unit on these properties when they're 0
|
|
35
|
-
const keepWhenZero = new Set([
|
|
36
|
-
'stroke-dashoffset',
|
|
37
|
-
'stroke-width',
|
|
38
|
-
'line-height',
|
|
39
|
-
]);
|
|
40
|
-
|
|
41
|
-
// Can't remove the % on these properties when they're 0 on IE 11
|
|
42
|
-
const keepZeroPercentOnIE11 = new Set(['max-height', 'height', 'min-width']);
|
|
43
|
-
|
|
44
|
-
const keepZeroPercentAlways = new Set([
|
|
45
|
-
'calc',
|
|
46
|
-
'color-mix',
|
|
47
|
-
'min',
|
|
48
|
-
'max',
|
|
49
|
-
'clamp',
|
|
50
|
-
'hsl',
|
|
51
|
-
'hsla',
|
|
52
|
-
'hwb',
|
|
53
|
-
'linear',
|
|
54
|
-
]);
|
|
55
|
-
|
|
56
|
-
const keepZeroPercentageInKeyframe = new Set([
|
|
57
|
-
'border-image-width',
|
|
58
|
-
'stroke-dasharray',
|
|
59
|
-
]);
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Numbers without digits after the dot are technically invalid,
|
|
63
|
-
* but in that case css-value-parser returns the dot as part of the unit,
|
|
64
|
-
* so we use this to remove the dot.
|
|
65
|
-
*
|
|
66
|
-
* @param {string} item
|
|
67
|
-
* @return {string}
|
|
68
|
-
*/
|
|
69
|
-
function stripLeadingDot(item) {
|
|
70
|
-
if (item.charCodeAt(0) === '.'.charCodeAt(0)) {
|
|
71
|
-
return item.slice(1);
|
|
72
|
-
} else {
|
|
73
|
-
return item;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* @param {valueParser.Node} node
|
|
79
|
-
* @param {Options} opts
|
|
80
|
-
* @param {boolean} keepZeroUnit
|
|
81
|
-
* @return {void}
|
|
82
|
-
*/
|
|
83
|
-
function parseWord(node, opts, keepZeroUnit) {
|
|
84
|
-
const pair = valueParser.unit(node.value);
|
|
85
|
-
if (pair) {
|
|
86
|
-
const num = Number(pair.number);
|
|
87
|
-
const u = stripLeadingDot(pair.unit);
|
|
88
|
-
if (num === 0) {
|
|
89
|
-
node.value =
|
|
90
|
-
0 +
|
|
91
|
-
(keepZeroUnit || (!LENGTH_UNITS.has(u.toLowerCase()) && u !== '%')
|
|
92
|
-
? u
|
|
93
|
-
: '');
|
|
94
|
-
if (node.value === '0ms') {
|
|
95
|
-
node.value = '0s';
|
|
96
|
-
}
|
|
97
|
-
} else {
|
|
98
|
-
node.value = convert(num, u, opts);
|
|
99
|
-
|
|
100
|
-
if (
|
|
101
|
-
typeof opts.precision === 'number' &&
|
|
102
|
-
u.toLowerCase() === 'px' &&
|
|
103
|
-
pair.number.includes('.')
|
|
104
|
-
) {
|
|
105
|
-
const precision = Math.pow(10, opts.precision);
|
|
106
|
-
node.value =
|
|
107
|
-
Math.round(Number.parseFloat(node.value) * precision) / precision + u;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* @param {valueParser.WordNode} node
|
|
115
|
-
* @return {void}
|
|
116
|
-
*/
|
|
117
|
-
function clampOpacity(node) {
|
|
118
|
-
const pair = valueParser.unit(node.value);
|
|
119
|
-
if (!pair) {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
const num = Number(pair.number);
|
|
123
|
-
if (num > 1) {
|
|
124
|
-
node.value = pair.unit === '%' ? num + pair.unit : 1 + pair.unit;
|
|
125
|
-
} else if (num < 0) {
|
|
126
|
-
node.value = 0 + pair.unit;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* @param {import('postcss').Declaration} decl
|
|
132
|
-
* @param {string[]} browsers
|
|
133
|
-
* @return {boolean}
|
|
134
|
-
*/
|
|
135
|
-
function shouldKeepZeroUnit(decl, browsers) {
|
|
136
|
-
const { parent } = decl;
|
|
137
|
-
const lowerCasedProp = decl.prop.toLowerCase();
|
|
138
|
-
|
|
139
|
-
return (
|
|
140
|
-
(decl.value.includes('%') &&
|
|
141
|
-
keepZeroPercentOnIE11.has(lowerCasedProp) &&
|
|
142
|
-
browsers.includes('ie 11')) ||
|
|
143
|
-
(keepZeroPercentageInKeyframe.has(lowerCasedProp) &&
|
|
144
|
-
parent &&
|
|
145
|
-
parent.parent &&
|
|
146
|
-
parent.parent.type === 'atrule' &&
|
|
147
|
-
/** @type {import('postcss').AtRule} */
|
|
148
|
-
(parent.parent).name.toLowerCase() === 'keyframes') ||
|
|
149
|
-
(lowerCasedProp === 'initial-value' &&
|
|
150
|
-
parent &&
|
|
151
|
-
parent.type === 'atrule' &&
|
|
152
|
-
parent.name === 'property' &&
|
|
153
|
-
parent.nodes !== undefined &&
|
|
154
|
-
parent.nodes.some(
|
|
155
|
-
(node) =>
|
|
156
|
-
node.type === 'decl' &&
|
|
157
|
-
node.prop.toLowerCase() === 'syntax' &&
|
|
158
|
-
(node.value === "'<percentage>'" ||
|
|
159
|
-
node.value === '"<percentage>"' ||
|
|
160
|
-
node.value === "'<length-percentage>'" ||
|
|
161
|
-
node.value === '"<length-percentage>"')
|
|
162
|
-
)) ||
|
|
163
|
-
keepWhenZero.has(lowerCasedProp)
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* @param {Options} opts
|
|
168
|
-
* @param {string[]} browsers
|
|
169
|
-
* @param {import('postcss').Declaration} decl
|
|
170
|
-
* @return {void}
|
|
171
|
-
*/
|
|
172
|
-
function transform(opts, browsers, decl) {
|
|
173
|
-
const lowerCasedProp = decl.prop.toLowerCase();
|
|
174
|
-
if (
|
|
175
|
-
lowerCasedProp.includes('flex') ||
|
|
176
|
-
(lowerCasedProp.indexOf('--') === 0 && !opts.transformCustomProperties) ||
|
|
177
|
-
notALength.has(lowerCasedProp)
|
|
178
|
-
) {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
decl.value = valueParser(decl.value)
|
|
183
|
-
.walk((node) => {
|
|
184
|
-
const lowerCasedValue = node.value.toLowerCase();
|
|
185
|
-
|
|
186
|
-
if (node.type === 'word') {
|
|
187
|
-
parseWord(node, opts, shouldKeepZeroUnit(decl, browsers));
|
|
188
|
-
if (
|
|
189
|
-
lowerCasedProp === 'opacity' ||
|
|
190
|
-
lowerCasedProp === 'shape-image-threshold'
|
|
191
|
-
) {
|
|
192
|
-
clampOpacity(node);
|
|
193
|
-
}
|
|
194
|
-
} else if (node.type === 'function') {
|
|
195
|
-
if (keepZeroPercentAlways.has(lowerCasedValue)) {
|
|
196
|
-
valueParser.walk(node.nodes, (n) => {
|
|
197
|
-
if (n.type === 'word') {
|
|
198
|
-
parseWord(n, opts, true);
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
|
-
return false;
|
|
202
|
-
}
|
|
203
|
-
if (lowerCasedValue === 'url') {
|
|
204
|
-
return false;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
})
|
|
208
|
-
.toString();
|
|
209
|
-
}
|
|
5
|
+
/** @import convert from './lib/convert.js' */
|
|
210
6
|
|
|
211
7
|
const plugin = 'postcss-convert-values';
|
|
212
8
|
|
|
@@ -217,28 +13,37 @@ const plugin = 'postcss-convert-values';
|
|
|
217
13
|
* @typedef {{precision?: false | number, transformCustomProperties?: boolean} & ConvertOptions & AutoprefixerOptions & BrowserslistOptions} Options
|
|
218
14
|
*/
|
|
219
15
|
|
|
220
|
-
/**
|
|
221
|
-
* @param {Options} opts
|
|
222
|
-
* @return {import('postcss').Plugin}
|
|
223
|
-
*/
|
|
16
|
+
/** @param {Options} opts @return {import('postcss').Plugin} */
|
|
224
17
|
function pluginCreator(opts = { precision: false }) {
|
|
18
|
+
/** @type {Map<string, boolean>} */
|
|
19
|
+
const browserCache = new Map();
|
|
20
|
+
|
|
225
21
|
return {
|
|
226
22
|
postcssPlugin: plugin,
|
|
227
23
|
|
|
228
|
-
/**
|
|
229
|
-
* @param {import('postcss').Result & {opts: BrowserslistOptions & {file?: string}}} result
|
|
230
|
-
*/
|
|
24
|
+
/** @param {import('postcss').Result & {opts: BrowserslistOptions & {file?: string}}} result */
|
|
231
25
|
prepare(result) {
|
|
232
26
|
const { stats, env, from, file } = result.opts || {};
|
|
233
|
-
const
|
|
234
|
-
|
|
27
|
+
const overrideKey = opts.overrideBrowserslist
|
|
28
|
+
? JSON.stringify(opts.overrideBrowserslist)
|
|
29
|
+
: '';
|
|
30
|
+
const pathKey = opts.path ?? '';
|
|
31
|
+
const envKey = opts.env ?? env ?? '';
|
|
32
|
+
const effectiveStats = opts.stats || stats;
|
|
33
|
+
const statsKey = effectiveStats ? JSON.stringify(effectiveStats) : '';
|
|
34
|
+
const cacheKey = `${overrideKey}\0${pathKey}\0${envKey}\0${from ?? ''}\0${file ?? ''}\0${statsKey}`;
|
|
35
|
+
let supportsIE = browserCache.get(cacheKey);
|
|
36
|
+
if (supportsIE === undefined) {
|
|
37
|
+
const browsers = getBrowsersList(opts, stats, from, file, env);
|
|
38
|
+
supportsIE = browsers.some((b) => b.startsWith('ie '));
|
|
39
|
+
browserCache.set(cacheKey, supportsIE);
|
|
40
|
+
}
|
|
41
|
+
const cache = new Map();
|
|
235
42
|
return {
|
|
236
|
-
/**
|
|
237
|
-
* @param {import('postcss').Root} css
|
|
238
|
-
*/
|
|
43
|
+
/** @param {import('postcss').Root} css */
|
|
239
44
|
OnceExit(css) {
|
|
240
45
|
css.walkDecls((decl) =>
|
|
241
|
-
transform(/** @type {Options} */ (opts),
|
|
46
|
+
transform(/** @type {Options} */ (opts), supportsIE, decl, cache)
|
|
242
47
|
);
|
|
243
48
|
},
|
|
244
49
|
};
|
package/src/lib/convert.js
CHANGED
|
@@ -1,26 +1,63 @@
|
|
|
1
|
-
const lengthConv = new Map([
|
|
2
|
-
['in',
|
|
3
|
-
['px',
|
|
4
|
-
['pt', 4
|
|
5
|
-
['pc',
|
|
1
|
+
export const lengthConv = new Map([
|
|
2
|
+
['in', 288],
|
|
3
|
+
['px', 3],
|
|
4
|
+
['pt', 4],
|
|
5
|
+
['pc', 48],
|
|
6
6
|
]);
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
export const metricConv = new Map([
|
|
9
|
+
['cm', 40],
|
|
10
|
+
['mm', 4],
|
|
11
|
+
['q', 1],
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
export const timeConv = new Map([
|
|
9
15
|
['s', 1000],
|
|
10
16
|
['ms', 1],
|
|
11
17
|
]);
|
|
12
18
|
|
|
13
|
-
const angleConv = new Map([
|
|
14
|
-
['
|
|
15
|
-
['
|
|
19
|
+
export const angleConv = new Map([
|
|
20
|
+
['deg', 10],
|
|
21
|
+
['turn', 3600],
|
|
22
|
+
['grad', 9],
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
export const freqConv = new Map([
|
|
26
|
+
['khz', 1000],
|
|
27
|
+
['hz', 1],
|
|
16
28
|
]);
|
|
17
29
|
|
|
18
|
-
/** @typedef {{time?: boolean, length?: boolean, angle?: boolean}} ConvertOptions */
|
|
30
|
+
/** @typedef {{time?: boolean, length?: boolean, angle?: boolean, frequency?: boolean}} ConvertOptions */
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Accurately round a number to a fixed decimal precision without IEEE-754 binary
|
|
34
|
+
* floating point multiplication errors.
|
|
35
|
+
*
|
|
36
|
+
* @param {number} value
|
|
37
|
+
* @param {number} precision
|
|
38
|
+
* @return {number}
|
|
39
|
+
*/
|
|
40
|
+
export function roundToPrecision(value, precision) {
|
|
41
|
+
if (
|
|
42
|
+
typeof precision !== 'number' ||
|
|
43
|
+
precision < 0 ||
|
|
44
|
+
!Number.isFinite(precision) ||
|
|
45
|
+
!Number.isFinite(value)
|
|
46
|
+
) {
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
const p = Math.floor(precision);
|
|
50
|
+
const [mantissa, exponent = 0] = String(value).toLowerCase().split('e');
|
|
51
|
+
const shifted = Number(mantissa + 'e' + (Number(exponent) + p));
|
|
52
|
+
const rounded = (Math.sign(shifted) || 0) * Math.round(Math.abs(shifted));
|
|
53
|
+
return Number(rounded + 'e-' + p);
|
|
54
|
+
}
|
|
55
|
+
|
|
19
56
|
/**
|
|
20
57
|
* @param {number} number
|
|
21
58
|
* @return {string}
|
|
22
59
|
*/
|
|
23
|
-
function dropLeadingZero(number) {
|
|
60
|
+
export function dropLeadingZero(number) {
|
|
24
61
|
const value = String(number);
|
|
25
62
|
|
|
26
63
|
if (number % 1) {
|
|
@@ -35,23 +72,23 @@ function dropLeadingZero(number) {
|
|
|
35
72
|
|
|
36
73
|
return value;
|
|
37
74
|
}
|
|
75
|
+
|
|
38
76
|
/**
|
|
39
77
|
* @param {number} number
|
|
40
78
|
* @param {string} originalUnit
|
|
41
|
-
* @param {typeof lengthConv | typeof timeConv | typeof angleConv} conversions
|
|
79
|
+
* @param {typeof lengthConv | typeof timeConv | typeof angleConv | typeof freqConv | typeof metricConv} conversions
|
|
42
80
|
* @return {string}
|
|
43
81
|
*/
|
|
44
|
-
function
|
|
45
|
-
const conversionUnits = [...conversions.keys()].filter((u) => {
|
|
46
|
-
return originalUnit !== u;
|
|
47
|
-
});
|
|
48
|
-
|
|
82
|
+
function findShortestConversion(number, originalUnit, conversions) {
|
|
49
83
|
const base = number * /** @type {number} */ (conversions.get(originalUnit));
|
|
50
84
|
|
|
51
85
|
let shortest = '';
|
|
52
|
-
for (const u of
|
|
53
|
-
|
|
54
|
-
|
|
86
|
+
for (const [u, factor] of conversions) {
|
|
87
|
+
if (u === originalUnit) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const convertedNumber = Number((base / factor).toPrecision(15));
|
|
91
|
+
const value = dropLeadingZero(convertedNumber) + u;
|
|
55
92
|
|
|
56
93
|
if (!shortest || value.length < shortest.length) {
|
|
57
94
|
shortest = value;
|
|
@@ -60,6 +97,22 @@ function transform(number, originalUnit, conversions) {
|
|
|
60
97
|
|
|
61
98
|
return shortest;
|
|
62
99
|
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @param {number} number
|
|
103
|
+
* @param {string} unit
|
|
104
|
+
* @return {string | undefined}
|
|
105
|
+
*/
|
|
106
|
+
function convertAngle(number, unit) {
|
|
107
|
+
if (unit === 'rad') {
|
|
108
|
+
return number === 0 ? '0deg' : undefined;
|
|
109
|
+
}
|
|
110
|
+
if (angleConv.has(unit)) {
|
|
111
|
+
return findShortestConversion(number, unit, angleConv);
|
|
112
|
+
}
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
|
|
63
116
|
/**
|
|
64
117
|
* @param {number} number
|
|
65
118
|
* @param {string} unit
|
|
@@ -67,24 +120,34 @@ function transform(number, originalUnit, conversions) {
|
|
|
67
120
|
* @return {string}
|
|
68
121
|
*/
|
|
69
122
|
const convert = function (number, unit, options) {
|
|
70
|
-
const { time, length, angle } = options;
|
|
71
|
-
let value = dropLeadingZero(number) + (unit ? unit : '');
|
|
72
|
-
let converted;
|
|
123
|
+
const { time, length, angle, frequency } = options;
|
|
73
124
|
const lowerCaseUnit = unit.toLowerCase();
|
|
125
|
+
let converted;
|
|
74
126
|
if (length !== false && lengthConv.has(lowerCaseUnit)) {
|
|
75
|
-
converted =
|
|
127
|
+
converted = findShortestConversion(number, lowerCaseUnit, lengthConv);
|
|
128
|
+
} else if (length !== false && metricConv.has(lowerCaseUnit)) {
|
|
129
|
+
converted = findShortestConversion(number, lowerCaseUnit, metricConv);
|
|
130
|
+
} else if (time !== false && timeConv.has(lowerCaseUnit)) {
|
|
131
|
+
converted = findShortestConversion(number, lowerCaseUnit, timeConv);
|
|
76
132
|
}
|
|
77
133
|
|
|
78
|
-
if (
|
|
79
|
-
converted =
|
|
134
|
+
if (!converted && angle !== false) {
|
|
135
|
+
converted = convertAngle(number, lowerCaseUnit);
|
|
136
|
+
}
|
|
137
|
+
if (!converted && frequency !== false && freqConv.has(lowerCaseUnit)) {
|
|
138
|
+
converted = findShortestConversion(number, lowerCaseUnit, freqConv);
|
|
80
139
|
}
|
|
81
140
|
|
|
82
|
-
|
|
83
|
-
|
|
141
|
+
const value = dropLeadingZero(number) + (unit ? unit : '');
|
|
142
|
+
if (!converted) {
|
|
143
|
+
return value;
|
|
84
144
|
}
|
|
85
145
|
|
|
86
|
-
if (
|
|
87
|
-
value
|
|
146
|
+
if (
|
|
147
|
+
converted.length < value.length ||
|
|
148
|
+
(lowerCaseUnit === 'rad' && converted.length <= value.length)
|
|
149
|
+
) {
|
|
150
|
+
return converted;
|
|
88
151
|
}
|
|
89
152
|
|
|
90
153
|
return value;
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import cssnanoUtils from 'cssnano-utils';
|
|
2
|
+
|
|
3
|
+
const { TokenType, decoded, tokens } = cssnanoUtils;
|
|
4
|
+
|
|
5
|
+
const percentageSyntaxTypes = new Set([
|
|
6
|
+
'percentage',
|
|
7
|
+
'length-percentage',
|
|
8
|
+
'angle-percentage',
|
|
9
|
+
'time-percentage',
|
|
10
|
+
'frequency-percentage',
|
|
11
|
+
]);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {ReturnType<typeof tokens>} tokensList
|
|
15
|
+
* @param {number} i
|
|
16
|
+
* @return {number}
|
|
17
|
+
*/
|
|
18
|
+
function skipTrivia(tokensList, i) {
|
|
19
|
+
let index = i;
|
|
20
|
+
while (index < tokensList.length) {
|
|
21
|
+
const type = tokensList[index][0];
|
|
22
|
+
if (type !== TokenType.Whitespace && type !== TokenType.Comment) {
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
index++;
|
|
26
|
+
}
|
|
27
|
+
return index;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {ReturnType<typeof tokens>} tokensList
|
|
32
|
+
* @param {number} startIndex
|
|
33
|
+
* @param {string} openType
|
|
34
|
+
* @param {string} closeType
|
|
35
|
+
* @return {number}
|
|
36
|
+
*/
|
|
37
|
+
function skipMatching(tokensList, startIndex, openType, closeType) {
|
|
38
|
+
let depth = 1;
|
|
39
|
+
let index = startIndex + 1;
|
|
40
|
+
while (index < tokensList.length) {
|
|
41
|
+
const type = tokensList[index][0];
|
|
42
|
+
if (type === openType) {
|
|
43
|
+
depth++;
|
|
44
|
+
} else if (type === closeType) {
|
|
45
|
+
depth--;
|
|
46
|
+
if (depth === 0) return index + 1;
|
|
47
|
+
}
|
|
48
|
+
index++;
|
|
49
|
+
}
|
|
50
|
+
return -1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @param {ReturnType<typeof tokens>} innerTokens
|
|
55
|
+
* @param {number} i
|
|
56
|
+
* @return {number}
|
|
57
|
+
*/
|
|
58
|
+
function consumeMultipliers(innerTokens, i) {
|
|
59
|
+
let index = i;
|
|
60
|
+
while (index < innerTokens.length) {
|
|
61
|
+
const token = innerTokens[index];
|
|
62
|
+
const type = token[0];
|
|
63
|
+
if (
|
|
64
|
+
type === TokenType.Delim &&
|
|
65
|
+
(token[1] === '+' ||
|
|
66
|
+
token[1] === '#' ||
|
|
67
|
+
token[1] === '?' ||
|
|
68
|
+
token[1] === '*' ||
|
|
69
|
+
token[1] === '!')
|
|
70
|
+
) {
|
|
71
|
+
index = skipTrivia(innerTokens, index + 1);
|
|
72
|
+
} else if (type === TokenType.OpenCurly) {
|
|
73
|
+
const next = skipMatching(
|
|
74
|
+
innerTokens,
|
|
75
|
+
index,
|
|
76
|
+
TokenType.OpenCurly,
|
|
77
|
+
TokenType.CloseCurly
|
|
78
|
+
);
|
|
79
|
+
if (next === -1) return -1;
|
|
80
|
+
index = skipTrivia(innerTokens, next);
|
|
81
|
+
} else {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return index;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @param {ReturnType<typeof tokens>} innerTokens
|
|
90
|
+
* @param {number} i
|
|
91
|
+
* @return {{nextIndex: number, hasPercentage: boolean} | undefined}
|
|
92
|
+
*/
|
|
93
|
+
function consumeComponent(innerTokens, i) {
|
|
94
|
+
const token = innerTokens[i];
|
|
95
|
+
if (!token) return undefined;
|
|
96
|
+
|
|
97
|
+
if (token[0] === TokenType.OpenSquare) {
|
|
98
|
+
const closeIndex = skipMatching(
|
|
99
|
+
innerTokens,
|
|
100
|
+
i,
|
|
101
|
+
TokenType.OpenSquare,
|
|
102
|
+
TokenType.CloseSquare
|
|
103
|
+
);
|
|
104
|
+
if (closeIndex === -1) return undefined;
|
|
105
|
+
const subTokens = innerTokens.slice(i + 1, closeIndex - 1);
|
|
106
|
+
const hasPercentage = scanSyntaxAllowsPercentage(subTokens);
|
|
107
|
+
let nextIndex = skipTrivia(innerTokens, closeIndex);
|
|
108
|
+
nextIndex = consumeMultipliers(innerTokens, nextIndex);
|
|
109
|
+
if (nextIndex === -1) return undefined;
|
|
110
|
+
return { nextIndex, hasPercentage };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (token[0] === TokenType.Ident) {
|
|
114
|
+
let nextIndex = skipTrivia(innerTokens, i + 1);
|
|
115
|
+
nextIndex = consumeMultipliers(innerTokens, nextIndex);
|
|
116
|
+
if (nextIndex === -1) return undefined;
|
|
117
|
+
return { nextIndex, hasPercentage: false };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (token[0] !== TokenType.Delim || token[1] !== '<') {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
const identIndex = skipTrivia(innerTokens, i + 1);
|
|
124
|
+
const ident = innerTokens[identIndex];
|
|
125
|
+
if (!ident || ident[0] !== TokenType.Ident) return undefined;
|
|
126
|
+
|
|
127
|
+
const hasPercentage = percentageSyntaxTypes.has(decoded(ident).toLowerCase());
|
|
128
|
+
let afterIdent = skipTrivia(innerTokens, identIndex + 1);
|
|
129
|
+
|
|
130
|
+
if (
|
|
131
|
+
afterIdent < innerTokens.length &&
|
|
132
|
+
innerTokens[afterIdent][0] === TokenType.OpenSquare
|
|
133
|
+
) {
|
|
134
|
+
afterIdent = skipMatching(
|
|
135
|
+
innerTokens,
|
|
136
|
+
afterIdent,
|
|
137
|
+
TokenType.OpenSquare,
|
|
138
|
+
TokenType.CloseSquare
|
|
139
|
+
);
|
|
140
|
+
if (afterIdent === -1) return undefined;
|
|
141
|
+
afterIdent = skipTrivia(innerTokens, afterIdent);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const close = innerTokens[afterIdent];
|
|
145
|
+
if (!close || close[0] !== TokenType.Delim || close[1] !== '>') {
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
let nextIndex = skipTrivia(innerTokens, afterIdent + 1);
|
|
150
|
+
nextIndex = consumeMultipliers(innerTokens, nextIndex);
|
|
151
|
+
if (nextIndex === -1) return undefined;
|
|
152
|
+
return { nextIndex, hasPercentage };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @param {ReturnType<typeof tokens>} innerTokens
|
|
157
|
+
* @param {number} i
|
|
158
|
+
* @return {number} next index, or -1 if invalid combinator
|
|
159
|
+
*/
|
|
160
|
+
function consumeCombinator(innerTokens, i) {
|
|
161
|
+
const sep = innerTokens[i];
|
|
162
|
+
if (sep[0] === TokenType.Delim && sep[1] === '|') {
|
|
163
|
+
let next = skipTrivia(innerTokens, i + 1);
|
|
164
|
+
if (
|
|
165
|
+
next < innerTokens.length &&
|
|
166
|
+
innerTokens[next][0] === TokenType.Delim &&
|
|
167
|
+
innerTokens[next][1] === '|'
|
|
168
|
+
) {
|
|
169
|
+
next = skipTrivia(innerTokens, next + 1);
|
|
170
|
+
}
|
|
171
|
+
return next >= innerTokens.length ? -1 : next;
|
|
172
|
+
}
|
|
173
|
+
if (sep[0] === TokenType.Delim && sep[1] === '&') {
|
|
174
|
+
let next = skipTrivia(innerTokens, i + 1);
|
|
175
|
+
if (
|
|
176
|
+
next < innerTokens.length &&
|
|
177
|
+
innerTokens[next][0] === TokenType.Delim &&
|
|
178
|
+
innerTokens[next][1] === '&'
|
|
179
|
+
) {
|
|
180
|
+
next = skipTrivia(innerTokens, next + 1);
|
|
181
|
+
return next >= innerTokens.length ? -1 : next;
|
|
182
|
+
}
|
|
183
|
+
return -1;
|
|
184
|
+
}
|
|
185
|
+
return i;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Parses an @property syntax string per CSS Properties and Values API Level 1 and CSS Values 4/5.
|
|
190
|
+
*
|
|
191
|
+
* @param {ReturnType<typeof tokens>} innerTokens
|
|
192
|
+
* @return {boolean}
|
|
193
|
+
*/
|
|
194
|
+
function scanSyntaxAllowsPercentage(innerTokens) {
|
|
195
|
+
let i = skipTrivia(innerTokens, 0);
|
|
196
|
+
if (i >= innerTokens.length) return true;
|
|
197
|
+
|
|
198
|
+
if (
|
|
199
|
+
innerTokens[i][0] === TokenType.Delim &&
|
|
200
|
+
innerTokens[i][1] === '*' &&
|
|
201
|
+
skipTrivia(innerTokens, i + 1) >= innerTokens.length
|
|
202
|
+
) {
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
let allowsPercentage = false;
|
|
207
|
+
while (i < innerTokens.length) {
|
|
208
|
+
const comp = consumeComponent(innerTokens, i);
|
|
209
|
+
if (!comp) return true;
|
|
210
|
+
if (comp.hasPercentage) allowsPercentage = true;
|
|
211
|
+
i = comp.nextIndex;
|
|
212
|
+
|
|
213
|
+
if (i < innerTokens.length) {
|
|
214
|
+
const nextIndex = consumeCombinator(innerTokens, i);
|
|
215
|
+
if (nextIndex === -1) return true;
|
|
216
|
+
i = nextIndex;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return allowsPercentage;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** @param {string} value @return {boolean} */
|
|
223
|
+
export function syntaxAllowsPercentage(value) {
|
|
224
|
+
const outerTokens = tokens(value);
|
|
225
|
+
let syntaxToken;
|
|
226
|
+
for (const token of outerTokens) {
|
|
227
|
+
if (token[0] === TokenType.Whitespace || token[0] === TokenType.Comment)
|
|
228
|
+
continue;
|
|
229
|
+
if (syntaxToken || token[0] !== TokenType.String) return true;
|
|
230
|
+
syntaxToken = token;
|
|
231
|
+
}
|
|
232
|
+
if (!syntaxToken) return true;
|
|
233
|
+
return scanSyntaxAllowsPercentage(tokens(decoded(syntaxToken)));
|
|
234
|
+
}
|
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
import cssnanoUtils from 'cssnano-utils';
|
|
2
|
+
import convert, {
|
|
3
|
+
dropLeadingZero,
|
|
4
|
+
roundToPrecision,
|
|
5
|
+
timeConv,
|
|
6
|
+
angleConv,
|
|
7
|
+
freqConv,
|
|
8
|
+
} from './convert.js';
|
|
9
|
+
import { syntaxAllowsPercentage } from './parse-syntax.js';
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
TokenType,
|
|
13
|
+
applyEdits,
|
|
14
|
+
calcSumFunctions,
|
|
15
|
+
closeForOpening,
|
|
16
|
+
decoded,
|
|
17
|
+
lengthUnits,
|
|
18
|
+
mathFunctions,
|
|
19
|
+
numericSource,
|
|
20
|
+
tokens,
|
|
21
|
+
} = cssnanoUtils;
|
|
22
|
+
|
|
23
|
+
const flexBasisProperties = new Set([
|
|
24
|
+
'flex',
|
|
25
|
+
'flex-basis',
|
|
26
|
+
'flex-basic',
|
|
27
|
+
'flex-preferred-size',
|
|
28
|
+
]);
|
|
29
|
+
const alphaProperties = new Set([
|
|
30
|
+
'opacity',
|
|
31
|
+
'shape-image-threshold',
|
|
32
|
+
'fill-opacity',
|
|
33
|
+
'stroke-opacity',
|
|
34
|
+
'stop-opacity',
|
|
35
|
+
'flood-opacity',
|
|
36
|
+
]);
|
|
37
|
+
const zeroPercentRetention = new Set([
|
|
38
|
+
'descent-override',
|
|
39
|
+
'ascent-override',
|
|
40
|
+
'font-stretch',
|
|
41
|
+
'font-width',
|
|
42
|
+
'size-adjust',
|
|
43
|
+
'line-gap-override',
|
|
44
|
+
'text-size-adjust',
|
|
45
|
+
'subscript-position-override',
|
|
46
|
+
'superscript-position-override',
|
|
47
|
+
'subscript-size-override',
|
|
48
|
+
'superscript-size-override',
|
|
49
|
+
'stroke-dasharray',
|
|
50
|
+
'stroke-dashoffset',
|
|
51
|
+
'stroke-width',
|
|
52
|
+
]);
|
|
53
|
+
const zeroUnitRetention = {
|
|
54
|
+
ie11Percent: new Set(['max-height', 'height', 'min-width']),
|
|
55
|
+
keyframePercent: new Set([
|
|
56
|
+
'border-image-width',
|
|
57
|
+
'stroke-dasharray',
|
|
58
|
+
'stroke-dashoffset',
|
|
59
|
+
'stroke-width',
|
|
60
|
+
]),
|
|
61
|
+
};
|
|
62
|
+
/* Functions in which a zero cannot lose its unit. Every math function qualifies
|
|
63
|
+
* because `calc(0%)` and `calc(0)` differ in type; the rest are listed per
|
|
64
|
+
* grammar, e.g. conic-gradient stops take an <angle-percentage>, which no
|
|
65
|
+
* unitless zero represents, while linear-gradient stops take a
|
|
66
|
+
* <length-percentage>, which it does. */
|
|
67
|
+
const functionsPreservingZeroUnits = new Set([
|
|
68
|
+
...mathFunctions,
|
|
69
|
+
...calcSumFunctions,
|
|
70
|
+
'anchor',
|
|
71
|
+
'anchor-size',
|
|
72
|
+
'contrast-color',
|
|
73
|
+
'view',
|
|
74
|
+
'color-mix',
|
|
75
|
+
'hsl',
|
|
76
|
+
'hsla',
|
|
77
|
+
'hwb',
|
|
78
|
+
'linear',
|
|
79
|
+
'conic-gradient',
|
|
80
|
+
'repeating-conic-gradient',
|
|
81
|
+
'cross-fade',
|
|
82
|
+
'rgb',
|
|
83
|
+
'rgba',
|
|
84
|
+
'oklch',
|
|
85
|
+
'oklab',
|
|
86
|
+
'lab',
|
|
87
|
+
'lch',
|
|
88
|
+
'color',
|
|
89
|
+
'palette-mix',
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
const convertibleUnits = new Set([
|
|
93
|
+
...timeConv.keys(),
|
|
94
|
+
...angleConv.keys(),
|
|
95
|
+
...freqConv.keys(),
|
|
96
|
+
'rad',
|
|
97
|
+
]);
|
|
98
|
+
|
|
99
|
+
/** @typedef {Parameters<typeof convert>[2]} ConvertOptions */
|
|
100
|
+
/** @typedef {{precision?: false | number, transformCustomProperties?: boolean} & ConvertOptions & { overrideBrowserslist?: string | string[] } & import('browserslist').Options} Options */
|
|
101
|
+
|
|
102
|
+
/** @param {number} number @param {string} unit @param {string} raw @param {Options} opts @param {boolean} keepZeroPercent @param {boolean} keepZeroLength @param {boolean} hasDecimal @return {string} */
|
|
103
|
+
function parseNumber(
|
|
104
|
+
number,
|
|
105
|
+
unit,
|
|
106
|
+
raw,
|
|
107
|
+
opts,
|
|
108
|
+
keepZeroPercent,
|
|
109
|
+
keepZeroLength,
|
|
110
|
+
hasDecimal
|
|
111
|
+
) {
|
|
112
|
+
if (raw.includes('\\')) return raw;
|
|
113
|
+
const lowerCasedUnit = unit.toLowerCase();
|
|
114
|
+
if (
|
|
115
|
+
unit !== '' &&
|
|
116
|
+
unit !== '%' &&
|
|
117
|
+
!lengthUnits.has(lowerCasedUnit) &&
|
|
118
|
+
!convertibleUnits.has(lowerCasedUnit)
|
|
119
|
+
)
|
|
120
|
+
return raw;
|
|
121
|
+
let num = number;
|
|
122
|
+
if (
|
|
123
|
+
typeof opts.precision === 'number' &&
|
|
124
|
+
opts.precision >= 0 &&
|
|
125
|
+
(hasDecimal || !Number.isInteger(num))
|
|
126
|
+
) {
|
|
127
|
+
num = roundToPrecision(num, opts.precision);
|
|
128
|
+
}
|
|
129
|
+
if (num === 0) {
|
|
130
|
+
if (convertibleUnits.has(lowerCasedUnit)) {
|
|
131
|
+
return convert(0, unit, opts);
|
|
132
|
+
}
|
|
133
|
+
if (unit === '%') {
|
|
134
|
+
return keepZeroPercent ? '0%' : '0';
|
|
135
|
+
}
|
|
136
|
+
if (lengthUnits.has(lowerCasedUnit)) {
|
|
137
|
+
return keepZeroLength ? '0' + unit : '0';
|
|
138
|
+
}
|
|
139
|
+
return '0';
|
|
140
|
+
}
|
|
141
|
+
return convert(num, unit, opts);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** @param {string} value @param {number} number @param {string} unit @param {Options} opts @param {boolean} [clamp] @return {string} */
|
|
145
|
+
function clampOpacity(value, number, unit, opts, clamp = true) {
|
|
146
|
+
if (unit === '%') {
|
|
147
|
+
if (clamp) {
|
|
148
|
+
if (number >= 100) return '1';
|
|
149
|
+
if (number <= 0) return '0';
|
|
150
|
+
}
|
|
151
|
+
let decimalNumber = Number((number / 100).toPrecision(15));
|
|
152
|
+
if (typeof opts.precision === 'number' && opts.precision >= 0) {
|
|
153
|
+
decimalNumber = roundToPrecision(decimalNumber, opts.precision);
|
|
154
|
+
}
|
|
155
|
+
const decimal = dropLeadingZero(decimalNumber);
|
|
156
|
+
return decimal.length < value.length ? decimal : value;
|
|
157
|
+
}
|
|
158
|
+
if (clamp) {
|
|
159
|
+
if (number > 1) return '1';
|
|
160
|
+
if (number < 0) return '0';
|
|
161
|
+
}
|
|
162
|
+
return value;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** @param {string} str @return {string} */
|
|
166
|
+
function stripVendorPrefix(str) {
|
|
167
|
+
if (str.charCodeAt(0) !== 45 /* '-' */) return str;
|
|
168
|
+
if (str.startsWith('-webkit-')) return str.slice(8);
|
|
169
|
+
if (str.startsWith('-moz-')) return str.slice(5);
|
|
170
|
+
if (str.startsWith('-ms-')) return str.slice(4);
|
|
171
|
+
if (str.startsWith('-o-')) return str.slice(3);
|
|
172
|
+
return str;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** @type {WeakMap<import('postcss').AtRule, boolean>} */
|
|
176
|
+
const atPropertySyntaxCache = new WeakMap();
|
|
177
|
+
|
|
178
|
+
/** @param {import('postcss').AtRule} parent @return {boolean} */
|
|
179
|
+
function atPropertyAllowsPercentage(parent) {
|
|
180
|
+
const cached = atPropertySyntaxCache.get(parent);
|
|
181
|
+
if (cached !== undefined) return cached;
|
|
182
|
+
|
|
183
|
+
const syntaxDecl = /** @type {import('postcss').Declaration | undefined} */ (
|
|
184
|
+
parent.nodes?.find(
|
|
185
|
+
(node) => node.type === 'decl' && node.prop.toLowerCase() === 'syntax'
|
|
186
|
+
)
|
|
187
|
+
);
|
|
188
|
+
const result = syntaxDecl ? syntaxAllowsPercentage(syntaxDecl.value) : true;
|
|
189
|
+
atPropertySyntaxCache.set(parent, result);
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** @param {import('postcss').Declaration} decl @return {boolean} */
|
|
194
|
+
function isInsideKeyframes(decl) {
|
|
195
|
+
let current = decl.parent;
|
|
196
|
+
while (current && current.type !== 'root') {
|
|
197
|
+
if (
|
|
198
|
+
current.type === 'atrule' &&
|
|
199
|
+
/** @type {import('postcss').AtRule} */ (current).name
|
|
200
|
+
.toLowerCase()
|
|
201
|
+
.endsWith('keyframes')
|
|
202
|
+
) {
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
current = current.parent;
|
|
206
|
+
}
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** @param {string} property @param {Options} opts @return {boolean} */
|
|
211
|
+
function skipsTransformation(property, opts) {
|
|
212
|
+
return property.startsWith('--') && !opts.transformCustomProperties;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* @param {import('postcss').Declaration} decl
|
|
217
|
+
* @param {string} lowerCasedProp
|
|
218
|
+
* @param {string} strippedProp
|
|
219
|
+
* @param {boolean | string[]} supportsIE
|
|
220
|
+
* @return {{keepZeroPercent: boolean, keepZeroLength: boolean, hasParentContext: boolean, clampAlpha: boolean}}
|
|
221
|
+
*/
|
|
222
|
+
function getDeclarationFlags(decl, lowerCasedProp, strippedProp, supportsIE) {
|
|
223
|
+
const isLineHeight = strippedProp === 'line-height';
|
|
224
|
+
const isFlexBasis = flexBasisProperties.has(strippedProp);
|
|
225
|
+
const isAtProperty =
|
|
226
|
+
lowerCasedProp === 'initial-value' &&
|
|
227
|
+
decl.parent?.type === 'atrule' &&
|
|
228
|
+
/** @type {import('postcss').AtRule} */ (decl.parent).name.toLowerCase() ===
|
|
229
|
+
'property';
|
|
230
|
+
const isAlphaProp = alphaProperties.has(strippedProp);
|
|
231
|
+
const isKeyframeProp = zeroUnitRetention.keyframePercent.has(strippedProp);
|
|
232
|
+
const inKeyframes =
|
|
233
|
+
(isKeyframeProp || isAlphaProp) && isInsideKeyframes(decl);
|
|
234
|
+
const hasParentContext = lowerCasedProp === 'initial-value' || inKeyframes;
|
|
235
|
+
|
|
236
|
+
const hasIESupport =
|
|
237
|
+
typeof supportsIE === 'boolean'
|
|
238
|
+
? supportsIE
|
|
239
|
+
: supportsIE.some((b) => b.startsWith('ie '));
|
|
240
|
+
|
|
241
|
+
const keepZeroPercent =
|
|
242
|
+
isLineHeight ||
|
|
243
|
+
isFlexBasis ||
|
|
244
|
+
zeroPercentRetention.has(strippedProp) ||
|
|
245
|
+
(hasIESupport && zeroUnitRetention.ie11Percent.has(strippedProp)) ||
|
|
246
|
+
(inKeyframes && isKeyframeProp) ||
|
|
247
|
+
(isAtProperty &&
|
|
248
|
+
atPropertyAllowsPercentage(
|
|
249
|
+
/** @type {import('postcss').AtRule} */ (decl.parent)
|
|
250
|
+
));
|
|
251
|
+
|
|
252
|
+
const keepZeroLength =
|
|
253
|
+
isLineHeight ||
|
|
254
|
+
isFlexBasis ||
|
|
255
|
+
strippedProp === 'columns' ||
|
|
256
|
+
strippedProp === 'flex-order' ||
|
|
257
|
+
isAtProperty;
|
|
258
|
+
|
|
259
|
+
const clampAlpha = !inKeyframes;
|
|
260
|
+
|
|
261
|
+
return { keepZeroPercent, keepZeroLength, hasParentContext, clampAlpha };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* @param {string} replacement
|
|
266
|
+
* @param {string} raw
|
|
267
|
+
* @param {boolean} isAlpha
|
|
268
|
+
* @param {boolean} isConvertibleZero
|
|
269
|
+
* @return {boolean}
|
|
270
|
+
*/
|
|
271
|
+
function shouldReplace(replacement, raw, isAlpha, isConvertibleZero) {
|
|
272
|
+
if (replacement === raw) return false;
|
|
273
|
+
if (replacement.length < raw.length) return true;
|
|
274
|
+
return (isAlpha || isConvertibleZero) && replacement.length <= raw.length;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
class FrameStack {
|
|
278
|
+
/** @type {string[]} */
|
|
279
|
+
#closeStack = [];
|
|
280
|
+
#keepZeroPercent;
|
|
281
|
+
#keepZeroLength;
|
|
282
|
+
#keepZeroUnitsDepth = -1;
|
|
283
|
+
#skippedDepth = -1;
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* @param {boolean} keepZeroPercent
|
|
287
|
+
* @param {boolean} keepZeroLength
|
|
288
|
+
*/
|
|
289
|
+
constructor(keepZeroPercent, keepZeroLength) {
|
|
290
|
+
this.#keepZeroPercent = keepZeroPercent;
|
|
291
|
+
this.#keepZeroLength = keepZeroLength;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
get isTopLevel() {
|
|
295
|
+
return this.#closeStack.length === 0;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
get isSkipped() {
|
|
299
|
+
return this.#skippedDepth !== -1;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
get keepZeroPercent() {
|
|
303
|
+
return this.#keepZeroPercent || this.#keepZeroUnitsDepth !== -1;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
get keepZeroLength() {
|
|
307
|
+
return this.#keepZeroLength || this.#keepZeroUnitsDepth !== -1;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* @param {ReturnType<typeof tokens>[number]} token
|
|
312
|
+
* @return {boolean}
|
|
313
|
+
*/
|
|
314
|
+
advance(token) {
|
|
315
|
+
const type = token[0];
|
|
316
|
+
if (type === TokenType.Function) {
|
|
317
|
+
const name = stripVendorPrefix(decoded(token).toLowerCase());
|
|
318
|
+
const keepInFunction = functionsPreservingZeroUnits.has(name);
|
|
319
|
+
const depth = this.#closeStack.length + 1;
|
|
320
|
+
this.#closeStack.push(TokenType.CloseParen);
|
|
321
|
+
if (keepInFunction && this.#keepZeroUnitsDepth === -1) {
|
|
322
|
+
this.#keepZeroUnitsDepth = depth;
|
|
323
|
+
}
|
|
324
|
+
if (name === 'url' && this.#skippedDepth === -1) {
|
|
325
|
+
this.#skippedDepth = depth;
|
|
326
|
+
}
|
|
327
|
+
return true;
|
|
328
|
+
}
|
|
329
|
+
if (
|
|
330
|
+
type === TokenType.OpenParen ||
|
|
331
|
+
type === TokenType.OpenSquare ||
|
|
332
|
+
type === TokenType.OpenCurly
|
|
333
|
+
) {
|
|
334
|
+
const close = closeForOpening(type);
|
|
335
|
+
if (close !== undefined) this.#closeStack.push(close);
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
if (
|
|
339
|
+
type === TokenType.CloseParen ||
|
|
340
|
+
type === TokenType.CloseSquare ||
|
|
341
|
+
type === TokenType.CloseCurly
|
|
342
|
+
) {
|
|
343
|
+
if (
|
|
344
|
+
this.#closeStack.length > 0 &&
|
|
345
|
+
this.#closeStack[this.#closeStack.length - 1] === type
|
|
346
|
+
) {
|
|
347
|
+
const depth = this.#closeStack.length;
|
|
348
|
+
if (depth === this.#keepZeroUnitsDepth) this.#keepZeroUnitsDepth = -1;
|
|
349
|
+
if (depth === this.#skippedDepth) this.#skippedDepth = -1;
|
|
350
|
+
this.#closeStack.pop();
|
|
351
|
+
}
|
|
352
|
+
return true;
|
|
353
|
+
}
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/** @typedef {{index: number, start: number, end: number, raw: string, number: number, unit: string, hasDecimal: boolean}} NumericSource */
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* @param {NumericSource} source
|
|
362
|
+
* @param {boolean} isLineHeight
|
|
363
|
+
* @param {string} strippedProp
|
|
364
|
+
* @param {FrameStack} frames
|
|
365
|
+
* @param {Options} opts
|
|
366
|
+
* @param {boolean} clampAlpha
|
|
367
|
+
* @return {{start: number, end: number, text: string} | undefined}
|
|
368
|
+
*/
|
|
369
|
+
function processNumericToken(
|
|
370
|
+
source,
|
|
371
|
+
isLineHeight,
|
|
372
|
+
strippedProp,
|
|
373
|
+
frames,
|
|
374
|
+
opts,
|
|
375
|
+
clampAlpha
|
|
376
|
+
) {
|
|
377
|
+
const currentKeepZeroPercent = frames.keepZeroPercent || isLineHeight;
|
|
378
|
+
const currentKeepZeroLength = frames.keepZeroLength || isLineHeight;
|
|
379
|
+
|
|
380
|
+
const converted = parseNumber(
|
|
381
|
+
source.number,
|
|
382
|
+
source.unit,
|
|
383
|
+
source.raw,
|
|
384
|
+
opts,
|
|
385
|
+
currentKeepZeroPercent,
|
|
386
|
+
currentKeepZeroLength,
|
|
387
|
+
source.hasDecimal
|
|
388
|
+
);
|
|
389
|
+
const isAlpha = alphaProperties.has(strippedProp) && frames.isTopLevel;
|
|
390
|
+
const replacement = isAlpha
|
|
391
|
+
? clampOpacity(converted, source.number, source.unit, opts, clampAlpha)
|
|
392
|
+
: converted;
|
|
393
|
+
const isConvertibleZero =
|
|
394
|
+
source.number === 0 && convertibleUnits.has(source.unit.toLowerCase());
|
|
395
|
+
|
|
396
|
+
if (shouldReplace(replacement, source.raw, isAlpha, isConvertibleZero)) {
|
|
397
|
+
return {
|
|
398
|
+
start: source.start,
|
|
399
|
+
end: source.end,
|
|
400
|
+
text: replacement,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
return undefined;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* @param {string} value
|
|
408
|
+
* @param {string} strippedProp
|
|
409
|
+
* @param {{keepZeroPercent: boolean, keepZeroLength: boolean, clampAlpha: boolean}} flags
|
|
410
|
+
* @param {Options} opts
|
|
411
|
+
* @return {{start: number, end: number, text: string}[]}
|
|
412
|
+
*/
|
|
413
|
+
function findReplacements(value, strippedProp, flags, opts) {
|
|
414
|
+
/** @type {{start: number, end: number, text: string}[]} */
|
|
415
|
+
const replacements = [];
|
|
416
|
+
const frames = new FrameStack(flags.keepZeroPercent, flags.keepZeroLength);
|
|
417
|
+
const isFont = strippedProp === 'font';
|
|
418
|
+
let afterFontSlash = false;
|
|
419
|
+
|
|
420
|
+
const input = tokens(value);
|
|
421
|
+
for (let index = 0; index < input.length; index++) {
|
|
422
|
+
const token = input[index];
|
|
423
|
+
if (frames.advance(token)) {
|
|
424
|
+
if (frames.isTopLevel && afterFontSlash) afterFontSlash = false;
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
if (frames.isSkipped) continue;
|
|
428
|
+
|
|
429
|
+
const type = token[0];
|
|
430
|
+
if (frames.isTopLevel) {
|
|
431
|
+
if (type === TokenType.Whitespace || type === TokenType.Comment) {
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
if (isFont && type === TokenType.Delim && token[1] === '/') {
|
|
435
|
+
afterFontSlash = true;
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const wasAfterFontSlash = frames.isTopLevel && afterFontSlash;
|
|
441
|
+
if (afterFontSlash) afterFontSlash = false;
|
|
442
|
+
|
|
443
|
+
if (
|
|
444
|
+
type !== TokenType.Number &&
|
|
445
|
+
type !== TokenType.Dimension &&
|
|
446
|
+
type !== TokenType.Percentage
|
|
447
|
+
) {
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
const source = numericSource(input, index);
|
|
452
|
+
if (!source) continue;
|
|
453
|
+
index = source.index;
|
|
454
|
+
|
|
455
|
+
const edit = processNumericToken(
|
|
456
|
+
source,
|
|
457
|
+
wasAfterFontSlash,
|
|
458
|
+
strippedProp,
|
|
459
|
+
frames,
|
|
460
|
+
opts,
|
|
461
|
+
flags.clampAlpha
|
|
462
|
+
);
|
|
463
|
+
if (edit) replacements.push(edit);
|
|
464
|
+
}
|
|
465
|
+
return replacements;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/** @param {import('postcss').Declaration} decl @param {string} newValue @return {void} */
|
|
469
|
+
function updateDeclValue(decl, newValue) {
|
|
470
|
+
decl.value = newValue;
|
|
471
|
+
if (decl.raws?.value?.raw) {
|
|
472
|
+
decl.raws.value = { raw: newValue, value: newValue };
|
|
473
|
+
} else if (decl.raws?.value) {
|
|
474
|
+
delete decl.raws.value;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/** @param {import('postcss').Declaration} decl @return {string} */
|
|
479
|
+
function getRawOrDeclarationValue(decl) {
|
|
480
|
+
const raw = decl.raws?.value;
|
|
481
|
+
return raw?.raw && raw.value === decl.value ? raw.raw : decl.value;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* @param {import('postcss').Declaration} decl
|
|
486
|
+
* @param {string} newValue
|
|
487
|
+
* @param {string} originalValue
|
|
488
|
+
* @return {void}
|
|
489
|
+
*/
|
|
490
|
+
function syncDeclValue(decl, newValue, originalValue) {
|
|
491
|
+
const isStale = Boolean(
|
|
492
|
+
decl.raws?.value && decl.raws.value.value !== decl.value
|
|
493
|
+
);
|
|
494
|
+
if (newValue !== originalValue || isStale) {
|
|
495
|
+
updateDeclValue(decl, newValue);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/** @param {Options} opts @param {boolean | string[]} supportsIE @param {import('postcss').Declaration} decl @param {Map<string, string>} [cache] @return {void} */
|
|
500
|
+
export default function transform(opts, supportsIE, decl, cache) {
|
|
501
|
+
const lowerCasedProp = decl.prop.toLowerCase();
|
|
502
|
+
if (skipsTransformation(lowerCasedProp, opts)) return;
|
|
503
|
+
const value = getRawOrDeclarationValue(decl);
|
|
504
|
+
if (!/[0-9]/v.test(value)) return;
|
|
505
|
+
|
|
506
|
+
const strippedProp = stripVendorPrefix(lowerCasedProp);
|
|
507
|
+
const flags = getDeclarationFlags(
|
|
508
|
+
decl,
|
|
509
|
+
lowerCasedProp,
|
|
510
|
+
strippedProp,
|
|
511
|
+
supportsIE
|
|
512
|
+
);
|
|
513
|
+
|
|
514
|
+
const cacheKey = flags.hasParentContext
|
|
515
|
+
? undefined
|
|
516
|
+
: `${lowerCasedProp}:${value}`;
|
|
517
|
+
if (cacheKey !== undefined && cache?.has(cacheKey)) {
|
|
518
|
+
const cached = /** @type {string} */ (cache.get(cacheKey));
|
|
519
|
+
syncDeclValue(decl, cached, value);
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const replacements = findReplacements(value, strippedProp, flags, opts);
|
|
524
|
+
const result = replacements.length ? applyEdits(value, replacements) : value;
|
|
525
|
+
if (cacheKey !== undefined) {
|
|
526
|
+
cache?.set(cacheKey, result);
|
|
527
|
+
}
|
|
528
|
+
syncDeclValue(decl, result, value);
|
|
529
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import convert from './lib/convert.js';
|
|
2
1
|
import type browserslist from 'browserslist';
|
|
2
|
+
import type convert from './lib/convert.js';
|
|
3
3
|
export type ConvertOptions = Parameters<typeof convert>[2];
|
|
4
4
|
export type AutoprefixerOptions = {
|
|
5
5
|
overrideBrowserslist?: string | string[];
|
|
@@ -15,10 +15,7 @@ export type Options = {
|
|
|
15
15
|
* @typedef {Pick<browserslist.Options, 'stats' | 'path' | 'env'>} BrowserslistOptions
|
|
16
16
|
* @typedef {{precision?: false | number, transformCustomProperties?: boolean} & ConvertOptions & AutoprefixerOptions & BrowserslistOptions} Options
|
|
17
17
|
*/
|
|
18
|
-
/**
|
|
19
|
-
* @param {Options} opts
|
|
20
|
-
* @return {import('postcss').Plugin}
|
|
21
|
-
*/
|
|
18
|
+
/** @param {Options} opts @return {import('postcss').Plugin} */
|
|
22
19
|
declare function pluginCreator(opts?: Options): import('postcss').Plugin;
|
|
23
20
|
declare namespace pluginCreator {
|
|
24
21
|
var postcss: true;
|
package/types/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"AAGI,OAAQ,KAAA,YAAY,MAAM,cAAc,CAAA;AACxC,OAAQ,KAAA,OAAO,MAAM,kBAAkB,CAAA;AAKxC,YAAyC,cAAc,GAA7C,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAgB;AACvD,YAAwD,mBAAmB,GAAjE;IAAE,oBAAoB,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAAE,CAAqB;AAC3E,YAAgE,mBAAmB,GAAzE,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC,CAAqB;AACnF,YAA0I,OAAO,GAAvI;IAAC,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAAC,yBAAyB,CAAC,EAAE,OAAO,CAAA;CAAC,GAAG,cAAc,GAAG,mBAAmB,GAAG,mBAAmB,CAAS;AAJpJ;;;;;GAKG;AAEH,+DAA+D;AAC/D,iBAAS,aAAa,CAAC,IAAI,GADf,OACsC,GADf,OAAO,SAAS,EAAE,MAAM,CAoC1D;kBAnCQ,aAAa;iBAoCX,IAAI;;AAEf,QAAA,MAAM,aAAa,sBAAgB,CAAC;AAEpC,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,aAAa,IAAI,gBAAgB,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"computeBrowsersToSupport.d.ts","sourceRoot":"","sources":["../../src/lib/computeBrowsersToSupport.js"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"computeBrowsersToSupport.d.ts","sourceRoot":"","sources":["../../src/lib/computeBrowsersToSupport.js"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,cAAc,CAAC;AAGxC;;;;;;;;GAQG;AACH,iBAAS,wBAAwB,CAAC,OAAO,EAP9B;IAAC,oBAAoB,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;IAAC,KAAK,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAAC,GAAG,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;CAOtI,EAAE,KAAK,EANrC,YAAY,CAAC,OAAO,CAAC,OAAO,CAMS,EAAE,IAAI,EAL3C,MAAM,GAAC,SAKoC,EAAE,IAAI,AAJzD,CACA,EADQ,MAIiD,EAAE,GAAG,AAH9D,CACA,EADQ,YAAY,CAAC,OAAO,CAAC,KAAK,CAG4B,GAFpD,MAAM,EAAE,CASpB;eAEc,wBAAwB"}
|
package/types/lib/convert.d.ts
CHANGED
|
@@ -1,8 +1,29 @@
|
|
|
1
|
+
export declare const lengthConv: Map<string, number>;
|
|
2
|
+
export declare const metricConv: Map<string, number>;
|
|
3
|
+
export declare const timeConv: Map<string, number>;
|
|
4
|
+
export declare const angleConv: Map<string, number>;
|
|
5
|
+
export declare const freqConv: Map<string, number>;
|
|
1
6
|
export type ConvertOptions = {
|
|
2
7
|
time?: boolean;
|
|
3
8
|
length?: boolean;
|
|
4
9
|
angle?: boolean;
|
|
10
|
+
frequency?: boolean;
|
|
5
11
|
};
|
|
12
|
+
/** @typedef {{time?: boolean, length?: boolean, angle?: boolean, frequency?: boolean}} ConvertOptions */
|
|
13
|
+
/**
|
|
14
|
+
* Accurately round a number to a fixed decimal precision without IEEE-754 binary
|
|
15
|
+
* floating point multiplication errors.
|
|
16
|
+
*
|
|
17
|
+
* @param {number} value
|
|
18
|
+
* @param {number} precision
|
|
19
|
+
* @return {number}
|
|
20
|
+
*/
|
|
21
|
+
export declare function roundToPrecision(value: number, precision: number): number;
|
|
22
|
+
/**
|
|
23
|
+
* @param {number} number
|
|
24
|
+
* @return {string}
|
|
25
|
+
*/
|
|
26
|
+
export declare function dropLeadingZero(number: number): string;
|
|
6
27
|
/**
|
|
7
28
|
* @param {number} number
|
|
8
29
|
* @param {string} unit
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../../src/lib/convert.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../../src/lib/convert.js"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,qBAKrB,CAAC;AAEH,eAAO,MAAM,UAAU,qBAIrB,CAAC;AAEH,eAAO,MAAM,QAAQ,qBAGnB,CAAC;AAEH,eAAO,MAAM,SAAS,qBAIpB,CAAC;AAEH,eAAO,MAAM,QAAQ,qBAGnB,CAAC;AAEC,YAAoF,cAAc,GAAxF;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAC,CAAgB;AAAtG,yGAAyG;AAEzG;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAJ3B,MAI2B,EAAE,SAAS,EAHtC,MAGsC,GAFrC,MAAM,CAgBjB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAH3B,MAG2B,GAF1B,MAAM,CAgBjB;AA0CD;;;;;GAKG;AACH,QAAA,MAAM,OAAO,WALF,MAAM,QACN,MAAM,WACN,cAAc,KACb,MAkCX,CAAC;eAEa,OAAO"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-syntax.d.ts","sourceRoot":"","sources":["../../src/lib/parse-syntax.js"],"names":[],"mappings":"AA6NA,8CAA8C;AAC9C,wBAAgB,sBAAsB,CAAC,KAAK,EADhC,MACgC,GADT,OAAO,CAYzC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import convert from './convert.js';
|
|
2
|
+
export type ConvertOptions = Parameters<typeof convert>[2];
|
|
3
|
+
export type Options = {
|
|
4
|
+
precision?: false | number;
|
|
5
|
+
transformCustomProperties?: boolean;
|
|
6
|
+
} & ConvertOptions & {
|
|
7
|
+
overrideBrowserslist?: string | string[];
|
|
8
|
+
} & import('browserslist').Options;
|
|
9
|
+
export type NumericSource = {
|
|
10
|
+
index: number;
|
|
11
|
+
start: number;
|
|
12
|
+
end: number;
|
|
13
|
+
raw: string;
|
|
14
|
+
number: number;
|
|
15
|
+
unit: string;
|
|
16
|
+
hasDecimal: boolean;
|
|
17
|
+
};
|
|
18
|
+
/** @param {Options} opts @param {boolean | string[]} supportsIE @param {import('postcss').Declaration} decl @param {Map<string, string>} [cache] @return {void} */
|
|
19
|
+
export default function transform(opts: Options, supportsIE: boolean | string[], decl: import('postcss').Declaration, cache?: Map<string, string>): void;
|
|
20
|
+
//# sourceMappingURL=transform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/lib/transform.js"],"names":[],"mappings":"AACA,OAAO,OAMN,MAAM,cAAc,CAAC;AA2FlB,YAAyC,cAAc,GAA7C,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAgB;AACvD,YAA8K,OAAO,GAA3K;IAAC,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAAC,yBAAyB,CAAC,EAAE,OAAO,CAAA;CAAC,GAAG,cAAc,GAAG;IAAE,oBAAoB,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAAE,GAAG,OAAO,cAAc,EAAE,OAAO,CAAS;AAkQrL,YAAuH,aAAa,GAA1H;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAC,CAAe;AA6IxI,mKAAmK;AACnK,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,IAAI,EAD1B,OAC0B,EAAE,UAAU,EADhB,OAAO,GAAG,MAAM,EACA,EAAE,IAAI,EADiB,OAAO,SAAS,EAAE,WACnC,EAAE,KAAK,AAD8C,CAAqC,EAA7B,GAAG,CAAC,MAAM,EAAE,MAAM,CACxE,GAD4F,IAAI,CA8B9J"}
|