-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
114 lines (99 loc) · 2.6 KB
/
index.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
105
106
107
108
109
110
111
112
113
114
'use strict'
const postcss = require('postcss')
// prefixes:
// - flex-shrink: 0; flex-grow: 0
// > - flex-shrink: 0; flex-grow: 1 (greedy)
// < - flex-shrink: 1; flex-grow: 0 (easily robbed)
// ~ - flex-shrink: 1; flex-grow: 1 (greedy but easily robbed)
const prefixes = {
'': [
{ prop: 'flex-grow', value: 0 },
{ prop: 'flex-shrink', value: 1 }
],
'>': [
{ prop: 'flex-grow', value: 1 },
{ prop: 'flex-shrink', value: 0 }
],
'=': [
{ prop: 'flex-grow', value: 0 },
{ prop: 'flex-shrink', value: 0 }
],
'~': [
{ prop: 'flex-grow', value: 1 },
{ prop: 'flex-shrink', value: 1 }
]
}
// suffixes:
// ! - overflow: initial (holds their own)
// ? - overflow: hidden (weak af)
const suffixes = {
'': [],
'!': [
{ prop: 'overflow', value: 'visible' }
],
'?': [
{ prop: 'overflow', value: 'hidden' }
]
}
// regexp for prefix, value and suffix
const chopRegexp = /([~>=]?)(.+)([?!]?)/
// decl is the "sushi-roll: x, y, z" declaration
// decl.parent is the rule that contains the declaration
const sushiRoll = decl => {
// split the value on commas and trim whitespaces
const values = decl.value.split(/\s*,\s*/)
// insert a new rule for each child
values.forEach((val, idx) => {
// parse the prefix, value and suffix
const m = val.match(chopRegexp)
if (!m) {
console.warn('Unrecognized input: "%s"', val)
return
}
// get the prefix, flex-basis and suffix
const prefix = m[1] || ''
const basis = m[2]
const suffix = m[3] || ''
// make the child rule
let selector = `${decl.parent.selector} > *:nth-child(${idx + 1})`
if (values.length === 1) {
selector = `${decl.parent.selector} > *`
}
const rule = postcss.rule({
selector: selector
})
// handle the flex-basis
rule.append({
prop: 'flex-basis',
value: basis
})
// handle the prefix
prefixes[prefix].forEach(prop => {
rule.append(prop)
})
// handle the suffix
suffixes[suffix].forEach(prop => {
rule.append(prop)
})
// add box-sizing: border-box
// TODO: make this optional, but enabled by default
rule.append({
prop: 'box-sizing',
value: 'border-box'
})
// add the child rule as a sibling of the sushi-roll rule
decl.parent.parent.append(rule)
})
// replace "sushi-roll: foo, bar" with "display: flex"
decl.replaceWith(postcss.decl({
prop: 'display',
value: 'flex'
}))
}
module.exports = postcss.plugin('postcss-sushi-roll', () => {
return (root, result) => {
root.walkDecls('sushi-roll', decl => {
sushiRoll(decl)
})
}
})