UNPKG

3.38 kBJavaScriptView Raw
1var postcss = require('postcss');
2var parser = require('postcss-selector-parser');
3
4function replace(nodes, parent) {
5 var replaced = false;
6 nodes.forEach(function (i) {
7 if (i.type === 'nesting') {
8 i.replaceWith(parent.clone());
9 replaced = true;
10 } else if (i.nodes) {
11 if (replace(i.nodes, parent)) {
12 replaced = true;
13 }
14 }
15 });
16 return replaced;
17}
18
19function selectors(parent, child) {
20 var result = [];
21 parent.selectors.forEach(function (i) {
22 var parentNode = parser().process(i).res.first;
23
24 child.selectors.forEach(function (j) {
25 var node = parser().process(j).res.first;
26 var replaced = replace(node.nodes, parentNode);
27 if (!replaced) {
28 node.prepend(parser.combinator({ value: ' ' }));
29 node.prepend(parentNode.clone());
30 }
31 result.push(node.toString());
32 });
33 });
34 return result;
35}
36
37function pickComment(comment, after) {
38 if ( comment && comment.type === 'comment' ) {
39 after.after(comment);
40 return comment;
41 } else {
42 return after;
43 }
44}
45
46function atruleChilds(rule, atrule) {
47 var children = [];
48 atrule.each(function (child) {
49 if ( child.type === 'comment' ) {
50 children.push( child );
51 } if ( child.type === 'decl' ) {
52 children.push( child );
53 } else if ( child.type === 'rule' ) {
54 child.selectors = selectors(rule, child);
55 } else if ( child.type === 'atrule' ) {
56 atruleChilds(rule, child);
57 }
58 });
59 if ( children.length ) {
60 var clone = rule.clone({ nodes: [] });
61 for ( var i = 0; i < children.length; i++ ) {
62 clone.append(children[i]);
63 }
64 atrule.prepend(clone);
65 }
66}
67
68function processRule(rule, bubble, preserveEmpty) {
69 var unwrapped = false;
70 var after = rule;
71 rule.each(function (child) {
72 if ( child.type === 'rule' ) {
73 unwrapped = true;
74 child.selectors = selectors(rule, child);
75 after = pickComment(child.prev(), after);
76 after.after(child);
77 after = child;
78 } else if ( child.type === 'atrule' ) {
79 if ( bubble.indexOf(child.name) !== -1 ) {
80 unwrapped = true;
81 atruleChilds(rule, child);
82 after = pickComment(child.prev(), after);
83 after.after(child);
84 after = child;
85 }
86 }
87 });
88 if ( unwrapped && preserveEmpty !== true ) {
89 rule.raws.semicolon = true;
90 if ( rule.nodes.length === 0 ) rule.remove();
91 }
92}
93
94module.exports = postcss.plugin('postcss-nested', function (opts) {
95 var bubble = ['media', 'supports', 'document'];
96 if ( opts && opts.bubble ) {
97 bubble = bubble.concat(opts.bubble.map(function (i) {
98 return i.replace(/^@/, '');
99 }));
100 }
101 var preserveEmpty = opts ? opts.preserveEmpty : false;
102
103 var process = function (node) {
104 node.each(function (child) {
105 if ( child.type === 'rule' ) {
106 processRule(child, bubble, preserveEmpty);
107 } else if ( child.type === 'atrule' ) {
108 process(child);
109 }
110 });
111 };
112 return process;
113});