boxBase.js
3.24 KB
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
105
106
107
108
109
110
111
112
113
114
115
116
117
'use strict';
const stylehacks = require('stylehacks');
const canMerge = require('../canMerge.js');
const getDecls = require('../getDecls.js');
const minifyTrbl = require('../minifyTrbl.js');
const parseTrbl = require('../parseTrbl.js');
const insertCloned = require('../insertCloned.js');
const mergeRules = require('../mergeRules.js');
const mergeValues = require('../mergeValues.js');
const trbl = require('../trbl.js');
const isCustomProp = require('../isCustomProp.js');
const canExplode = require('../canExplode.js');
/**
* @param {string} prop
* @return {{explode: (rule: import('postcss').Rule) => void, merge: (rule: import('postcss').Rule) => void}}
*/
module.exports = (prop) => {
const properties = trbl.map((direction) => `${prop}-${direction}`);
/** @type {(rule: import('postcss').Rule) => void} */
const cleanup = (rule) => {
let decls = getDecls(rule, [prop].concat(properties));
while (decls.length) {
const lastNode = decls[decls.length - 1];
// remove properties of lower precedence
const lesser = decls.filter(
(node) =>
!stylehacks.detect(lastNode) &&
!stylehacks.detect(node) &&
node !== lastNode &&
node.important === lastNode.important &&
lastNode.prop === prop &&
node.prop !== lastNode.prop
);
for (const node of lesser) {
node.remove();
}
decls = decls.filter((node) => !lesser.includes(node));
// get duplicate properties
let duplicates = decls.filter(
(node) =>
!stylehacks.detect(lastNode) &&
!stylehacks.detect(node) &&
node !== lastNode &&
node.important === lastNode.important &&
node.prop === lastNode.prop &&
!(!isCustomProp(node) && isCustomProp(lastNode))
);
for (const node of duplicates) {
node.remove();
}
decls = decls.filter(
(node) => node !== lastNode && !duplicates.includes(node)
);
}
};
const processor = {
/** @type {(rule: import('postcss').Rule) => void} */
explode: (rule) => {
rule.walkDecls(new RegExp('^' + prop + '$', 'i'), (decl) => {
if (!canExplode(decl)) {
return;
}
if (stylehacks.detect(decl)) {
return;
}
const values = parseTrbl(decl.value);
trbl.forEach((direction, index) => {
insertCloned(
/** @type {import('postcss').Rule} */ (decl.parent),
decl,
{
prop: properties[index],
value: values[index],
}
);
});
decl.remove();
});
},
/** @type {(rule: import('postcss').Rule) => void} */
merge: (rule) => {
mergeRules(rule, properties, (rules, lastNode) => {
if (canMerge(rules) && !rules.some(stylehacks.detect)) {
insertCloned(
/** @type {import('postcss').Rule} */ (lastNode.parent),
lastNode,
{
prop,
value: minifyTrbl(mergeValues(...rules)),
}
);
for (const node of rules) {
node.remove();
}
return true;
}
return false;
});
cleanup(rule);
},
};
return processor;
};