Skip to content

Commit e2b4874

Browse files
committed
add nesting. Closes reworkcss#2
1 parent 8e65fec commit e2b4874

File tree

9 files changed

+4664
-15
lines changed

9 files changed

+4664
-15
lines changed

examples/benchmark.css

+4,457
Large diffs are not rendered by default.

examples/nesting.css

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
body
3+
background: #888
4+
color: #eee
5+
6+
ul
7+
margin: 0
8+
li
9+
color: white
10+
a
11+
color: blue
12+
13+
@media print
14+
body
15+
width: 100px
16+
ul
17+
width: 50px
18+
li
19+
list-style: disc

examples/nesting.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
/**
3+
* Module dependencies.
4+
*/
5+
6+
var fs = require('fs')
7+
, compile = require('..')
8+
, read = fs.readFileSync
9+
10+
var str = read('examples/nesting.css', 'utf8');
11+
var css = compile(str);
12+
console.log(css);

lib/compiler.js

+107-15
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ var debug = require('debug')('css-whitespace:parser')
1616

1717
module.exports = function(node){
1818
var indents = 1;
19+
var rules = [];
20+
var stash = [];
21+
var level = 0;
22+
var nest = 0;
1923

2024
if (debug.enabled) {
2125
console.log(util.inspect(node, false, 12, true));
@@ -32,9 +36,15 @@ module.exports = function(node){
3236
case 'root':
3337
return root(node);
3438
case 'rule':
35-
return rule(node);
39+
if ('@' == node[1][0]) ++nest;
40+
var ret = rule(node);
41+
if ('@' == node[1][0]) --nest;
42+
return ret;
3643
case 'block':
37-
return block(node);
44+
++level;
45+
var ret = block(node);
46+
--level;
47+
return ret;
3848
case 'prop':
3949
return prop(node);
4050
default:
@@ -47,11 +57,14 @@ module.exports = function(node){
4757
*/
4858

4959
function block(node) {
60+
var buf = [];
5061
var nodes = node[1];
51-
++indents;
52-
var ret = nodes.map(visit).join('\n');
53-
--indents;
54-
return ret;
62+
63+
for (var i = 0; i < nodes.length; ++i) {
64+
buf.push(visit(nodes[i]));
65+
}
66+
67+
return buf.join('');
5568
}
5669

5770
/**
@@ -61,7 +74,7 @@ module.exports = function(node){
6174
function prop(node) {
6275
var prop = node[1];
6376
var val = node[2];
64-
return indent() + prop + ': ' + val + ';';
77+
return indent() + prop + ': ' + val + ';\n';
6578
}
6679

6780
/**
@@ -74,10 +87,34 @@ module.exports = function(node){
7487

7588
if (!block) return rule + ';';
7689

77-
return indent() + rule + ' {\n'
78-
+ visit(block)
79-
+ '\n'
80-
+ indent() + '}';
90+
rules.push(node);
91+
92+
if ('@' == rule[0]) {
93+
var buf = join(rules) + '{\n'
94+
visit(block);
95+
buf += stash.join('\n');
96+
buf += '\n}';
97+
stash = [];
98+
} else if (nest) {
99+
indents = 2;
100+
var buf = ' ' + join(rules, 1) + '{\n';
101+
buf += visit(block);
102+
buf += ' }';
103+
indents = 1;
104+
} else {
105+
var buf = join(rules) + '{\n'
106+
+ visit(block)
107+
+ '}';
108+
}
109+
110+
if (rules.length > 1) {
111+
if (hasProperties(block)) stash.push(buf);
112+
buf = '';
113+
}
114+
115+
rules.pop();
116+
117+
return buf;
81118
}
82119

83120
/**
@@ -86,17 +123,72 @@ module.exports = function(node){
86123

87124
function root(node) {
88125
var buf = [];
89-
for (var i=0; i < node[1].length; ++i) {
126+
for (var i = 0; i < node[1].length; ++i) {
90127
buf.push(visit(node[1][i]));
128+
if (stash.length) {
129+
buf = buf.concat(stash);
130+
stash = [];
131+
}
91132
}
92133
return buf.join('\n\n');
93134
}
94135

95136
/**
96-
* Return current indent.
137+
* Return indent.
97138
*/
98139

99140
function indent() {
100-
return Array(indents).join(' ');
141+
return Array(indents + 1).join(' ');
142+
}
143+
};
144+
145+
/**
146+
* Join the given rules.
147+
*
148+
* @param {Array} rules
149+
* @param {Number} [offset]
150+
* @return {String}
151+
* @api private
152+
*/
153+
154+
function join(rules, offset) {
155+
var buf = '';
156+
var curr;
157+
var next;
158+
159+
for (var i = offset || 0; i < rules.length; ++i) {
160+
curr = rules[i];
161+
next = rules[i + 1];
162+
buf += curr[1];
163+
if (next && next.parent) continue;
164+
buf += ' ';
101165
}
102-
};
166+
167+
return buf;
168+
}
169+
170+
/**
171+
* Check if `block` has properties.
172+
*
173+
* @param {Array} block
174+
* @return {Boolean}
175+
* @api private
176+
*/
177+
178+
function hasProperties(block) {
179+
var nodes = block[1];
180+
for (var i = 0; i < nodes.length; ++i) {
181+
if ('prop' == nodes[i][0]) return true;
182+
}
183+
return false;
184+
}
185+
186+
/**
187+
* Blank string filter.
188+
*
189+
* @api private
190+
*/
191+
192+
function blank(str) {
193+
return '' != str;
194+
}

lib/lexer.js

+14
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ module.exports = function(str) {
4646
|| blank()
4747
|| comment()
4848
|| indentation()
49+
|| parent()
4950
|| prop()
5051
|| rule();
5152
}
@@ -123,6 +124,19 @@ module.exports = function(str) {
123124
return stashed();
124125
}
125126

127+
/**
128+
* &<val>
129+
*/
130+
131+
function parent() {
132+
var m = str.match(/^ *&([^\n]*)/);
133+
if (!m) return;
134+
str = str.slice(m[0].length);
135+
var ret = ['rule', m[1]];
136+
ret.parent = true;
137+
return ret;
138+
}
139+
126140
/**
127141
* <prop>: <val>
128142
*/

test/cases/media.css

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
body
3+
padding: 50px
4+
5+
@media print
6+
body
7+
padding: 0
8+
9+
ul
10+
li a
11+
color: blue
12+
text-decoration: underline

test/cases/media.out.css

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
body {
2+
padding: 50px;
3+
}
4+
5+
@media print {
6+
body {
7+
padding: 0;
8+
}
9+
ul li a {
10+
color: blue;
11+
text-decoration: underline;
12+
}
13+
}

test/cases/nesting.out.css

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
body {
2+
padding: 50px;
3+
}
4+
5+
body ul li a {
6+
color: blue;
7+
}
8+
9+
body ul li {
10+
list-style: none;
11+
}
12+
13+
body ul {
14+
margin: 0;
15+
padding: 0;
16+
}

test/cases/parent.out.css

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
ul {
2+
}
3+
4+
ul li:hover {
5+
background: white;
6+
}
7+
8+
ul li:active {
9+
background: #ddd;
10+
}
11+
12+
ul li {
13+
background: #eee;
14+
}

0 commit comments

Comments
 (0)