-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
Copy pathcleanupNumericValues.js
104 lines (92 loc) · 2.76 KB
/
cleanupNumericValues.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import { removeLeadingZero } from '../lib/svgo/tools.js';
export const name = 'cleanupNumericValues';
export const description =
'rounds numeric values to the fixed precision, removes default ‘px’ units';
const regNumericValues =
/^([-+]?\d*\.?\d+([eE][-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/;
const absoluteLengths = {
// relative to px
cm: 96 / 2.54,
mm: 96 / 25.4,
in: 96,
pt: 4 / 3,
pc: 16,
px: 1,
};
/**
* Round numeric values to the fixed precision,
* remove default 'px' units.
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'cleanupNumericValues'>}
*/
export const fn = (_root, params) => {
const {
floatPrecision = 3,
leadingZero = true,
defaultPx = true,
convertToPx = true,
} = params;
return {
element: {
enter: (node) => {
if (node.attributes.viewBox != null) {
const nums = node.attributes.viewBox.trim().split(/(?:\s,?|,)\s*/g);
node.attributes.viewBox = nums
.map((value) => {
const num = Number(value);
return Number.isNaN(num)
? value
: Number(num.toFixed(floatPrecision));
})
.join(' ');
}
for (const [name, value] of Object.entries(node.attributes)) {
// The `version` attribute is a text string and cannot be rounded
if (name === 'version') {
continue;
}
const match = regNumericValues.exec(value);
// if attribute value matches regNumericValues
if (match) {
// round it to the fixed precision
let num = Number(Number(match[1]).toFixed(floatPrecision));
/**
* @type {any}
*/
let matchedUnit = match[3] || '';
/**
* @type{'' | keyof typeof absoluteLengths}
*/
let units = matchedUnit;
// convert absolute values to pixels
if (convertToPx && units !== '' && units in absoluteLengths) {
const pxNum = Number(
(absoluteLengths[units] * Number(match[1])).toFixed(
floatPrecision,
),
);
if (pxNum.toString().length < match[0].length) {
num = pxNum;
units = 'px';
}
}
// and remove leading zero
let str;
if (leadingZero) {
str = removeLeadingZero(num);
} else {
str = num.toString();
}
// remove default 'px' units
if (defaultPx && units === 'px') {
units = '';
}
node.attributes[name] = str + units;
}
}
},
},
};
};