-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathpostcss-fix-host-pseudo.js
More file actions
75 lines (73 loc) · 2.31 KB
/
postcss-fix-host-pseudo.js
File metadata and controls
75 lines (73 loc) · 2.31 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
'use strict';
const postcss = require('postcss');
const parser = require('postcss-selector-parser');
/**
* Below Sass code yields `:hover:host(bx-foo) svg` and `:host(bx-foo):hover svg` selectors.
* We want `:host(bx-foo:hover)` instead.
*
* Though generating `:host(bx-foo:hover)` from below Sass code is not what Sass language intends,
* `:hover:host(bx-foo) svg` or `:host(bx-foo):hover svg` is not meangful in real world.
* Therefore this PostCSS plugin converts `:hover:host(bx-foo) svg` and `:host(bx-foo):hover svg` to `:host(bx-foo:hover)`.
*
* ```scss
* .bx--foo {
* &:hover {
* svg {
* fill: white;
* }
* }
* }
*
* :host(bx-foo) {
* @extend .bx--foo;
* }
*
* :host(bx-foo) {
* &:hover {
* svg {
* fill: white;
* }
* }
* }
* ```
*/
// eslint-disable-next-line prefer-arrow-callback
module.exports = postcss.plugin('fix-host-pseudo', function postCssPluginFixHostPseudo() {
return function fixHostPseudo(css) {
css.walkRules(async rule => {
await parser(selectors => {
selectors.walkPseudos(pseudo => {
if (pseudo.value === ':host') {
if (pseudo.nodes.length !== 1 || pseudo.first.type !== 'selector') {
// eslint-disable-next-line no-console
console.warn('Found :host() with more than one child or with a non-selector child. Skipping...');
} else {
const pseudosToMove = [];
for (
let precedingNode = pseudo.prev();
precedingNode && precedingNode.type !== 'combinator';
precedingNode = precedingNode.prev()
) {
pseudosToMove.unshift(precedingNode);
}
for (
let followingNode = pseudo.next();
followingNode && followingNode.type !== 'combinator';
followingNode = followingNode.next()
) {
pseudosToMove.push(followingNode);
}
pseudosToMove.forEach(item => {
const newNode = item.clone();
newNode.spaces.before = '';
newNode.spaces.after = '';
pseudo.first.append(newNode);
item.remove();
});
}
}
});
}).process(rule);
});
};
});