index.js
3.35 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
118
119
120
121
122
123
124
125
126
let valueParser = require('postcss-value-parser')
function parseValue (value) {
let parsed = value.match(/([\d.-]+)(.*)/)
if (!parsed || !parsed[1] || !parsed[2] || isNaN(parsed[1])) {
return undefined
}
return [parseFloat(parsed[1]), parsed[2]]
}
function compose (first, second, third) {
if (first && second && third) {
return `max(${first}, min(${second}, ${third}))`
}
if (first && second) {
return `max(${first}, ${second})`
}
return first
}
function updateValue (declaration, value, preserve) {
let newValue = value
let newValueAst = valueParser(value)
let valueAST = valueParser(declaration.value)
// Walk can't be interrupted, so we only care about first
let foundClamp = false
valueAST.walk((node, index, nodes) => {
let isClamp = node.type === 'function' && node.value === 'clamp'
if (!isClamp || foundClamp) {
return
}
foundClamp = true
nodes[index] = newValueAst
})
if (foundClamp) {
newValue = valueAST.toString()
}
if (preserve) {
declaration.cloneBefore({ value: newValue })
} else {
declaration.value = newValue
}
}
module.exports = opts => {
opts = opts || {}
let precalculate = opts.precalculate ? Boolean(opts.precalculate) : false
let preserve = opts.preserve ? Boolean(opts.preserve) : false
return {
postcssPlugin: 'postcss-clamp',
Declaration (decl) {
if (!decl || !decl.value.includes('clamp')) {
return
}
valueParser(decl.value).walk(node => {
let nodes = node.nodes
if (
node.type !== 'function' ||
node.value !== 'clamp' ||
nodes.length !== 5
) {
return
}
let first = nodes[0]
let second = nodes[2]
let third = nodes[4]
let naive = compose(
valueParser.stringify(first),
valueParser.stringify(second),
valueParser.stringify(third)
)
if (!precalculate || second.type !== 'word' || third.type !== 'word') {
updateValue(decl, naive, preserve)
return
}
let parsedSecond = parseValue(second.value)
let parsedThird = parseValue(third.value)
if (parsedSecond === undefined || parsedThird === undefined) {
updateValue(decl, naive, preserve)
return
}
let [secondValue, secondUnit] = parsedSecond
let [thirdValue, thirdUnit] = parsedThird
if (secondUnit !== thirdUnit) {
updateValue(decl, naive, preserve)
return
}
let parsedFirst = parseValue(first.value)
if (parsedFirst === undefined) {
let secondThirdValue = `${secondValue + thirdValue}${secondUnit}`
updateValue(
decl,
compose(valueParser.stringify(first), secondThirdValue),
preserve
)
return
}
let [firstValue, firstUnit] = parsedFirst
if (firstUnit !== secondUnit) {
let secondThirdValue = `${secondValue + thirdValue}${secondUnit}`
updateValue(
decl,
compose(valueParser.stringify(first), secondThirdValue),
preserve
)
return
}
updateValue(
decl,
compose(`${firstValue + secondValue + thirdValue}${secondUnit}`),
preserve
)
})
}
}
}
module.exports.postcss = true