Skip to content

Commit e81c64f

Browse files
committed
v0.0.15
2 parents a271be9 + b48b99e commit e81c64f

File tree

11 files changed

+289
-32
lines changed

11 files changed

+289
-32
lines changed

.csscomb.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"element-case": "lower",
1313
"eof-newline": true,
1414
"leading-zero": false,
15+
"remove-empty-rulesets": true,
1516
"rule-indent": true,
1617
"stick-brace": "\n",
1718
"strip-spaces": true,

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ node_modules
22

33
.idea
44
*.iml
5+
6+
.DS_Store

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## 0.0.15 - 2013-10-03
4+
- Option: remove-empty-rulesets (#67)
5+
- Option colon-space expanded
6+
- Some refactoring and fixes
7+
38
## 0.0.14 - 2013-09-12
49
- Option: eof-newline (#55)
510
- Verbose option (#62)

README.md

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ Example configuration:
4242
"exclude": ["node_modules/**"],
4343
"verbose": true,
4444

45+
"remove-empty-rulesets": true,
4546
"always-semicolon": true,
4647
"block-indent": true,
4748
"colon-space": true,
@@ -59,6 +60,14 @@ Example configuration:
5960
6061
## Options
6162
63+
### exclude
64+
65+
Available values: `{String[]}`
66+
67+
Array of [Ant path patterns](http://ant.apache.org/manual/dirtasks.html#patterns) to exclude.
68+
69+
Example: `{ "exclude": ["node_modules/**"] }` - exclude all files and directories under `node_modules` dir.
70+
6271
### verbose
6372
6473
Available value: `{Boolean}` `true`
@@ -80,6 +89,14 @@ $ ./bin/csscomb ./test --verbose
8089
$ ./bin/csscomb ./test -v
8190
```
8291
92+
### remove-empty-rulesets
93+
94+
Available values: `{Boolean}` `true`
95+
96+
Example: `{ "remove-empty-rulesets": true }` - remove rulesets that have no declarations or comments.
97+
98+
`a { color: red; } p { /* hey */ } b { }` → `a { color: red; } p { /* hey */ } `
99+
83100
### always-semicolon
84101
85102
Available value: `{Boolean}` `true`
@@ -122,9 +139,10 @@ a { color: red
122139
### colon-space
123140
124141
Available values:
125-
* `{Boolean}` `true` (means `after`)
142+
* `{Boolean}` `true` (means `after`) or `false` (no whitespace at all)
126143
* `{String}`: `before`, `after`, `both` or any combination of whitespaces
127144
and/or a colon (` `, `: `, `\t:\n\t` etc.)
145+
* `{Array}` with two `{String}` values: for setting left and right whitespace around a colon
128146
129147
Example: `{ "colon-space": true }`
130148
@@ -151,7 +169,7 @@ a {
151169
}
152170
```
153171
154-
Example: `{ "colon-space": ":" }`
172+
Example: `{ "colon-space": "" }`
155173
156174
```css
157175
/* before */
@@ -161,6 +179,16 @@ a { color: red }
161179
a { color:red }
162180
```
163181
182+
Example: `{ "colon-space": ["\t", "\t"] }`
183+
184+
```css
185+
/* before */
186+
a { color: red }
187+
188+
/* after */
189+
a { color : red }
190+
```
191+
164192
### color-case
165193
166194
Available values: `{String}` `lower` or `upper`
@@ -405,3 +433,4 @@ This software is released under the terms of the [MIT license](https://github.co
405433
* https://github.com/senchalabs/cssbeautify
406434
* https://github.com/css/gonzales
407435
* https://github.com/css/csso
436+
* https://github.com/nzakas/parser-lib

lib/csscomb.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ var vfs = require('vow-fs');
1111
*/
1212
var Comb = function() {
1313
this._options = [
14+
'remove-empty-rulesets',
1415
'always-semicolon',
1516
'color-case',
1617
'color-shorthand',
@@ -76,23 +77,25 @@ Comb.prototype = {
7677
* @param {Number} level Indent level
7778
*/
7879
processNode: function(node, level) {
79-
var _this = this;
8080
node.forEach(function(node) {
8181
if (!Array.isArray(node)) return;
82+
8283
var nodeType = node.shift();
83-
_this._handlers.forEach(function(handler) {
84+
this._handlers.forEach(function(handler) {
8485
handler.process(nodeType, node, level);
8586
});
8687
node.unshift(nodeType);
88+
8789
if (nodeType === 'atrulers') level++;
88-
_this.processNode(node, level);
89-
});
90+
91+
this.processNode(node, level);
92+
}, this);
9093
},
9194

9295
/**
9396
* Process file provided with a string.
9497
* @param {String} text
95-
* @param {String} filename
98+
* @param {String} [filename]
9699
*/
97100
processString: function(text, filename) {
98101
if (!text) return text;

lib/options/colon-space.js

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,33 @@ module.exports = {
88
*/
99
setValue: function(value) {
1010
this._value = false;
11-
if (value === true) this._value = 'after';
12-
if (typeof value === 'string'&& value.match(/after|before|both|(?=.*(?:[ \t\n]|:))[ \t\n]*:?[ \t\n]*/)) {
11+
if (value === true)
12+
value = 'after';
13+
if (value === false)
14+
value = '';
15+
if (value === 'both')
16+
this._value = [' ', ' '];
17+
if (value === 'before')
18+
this._value = [' ', ''];
19+
if (value === 'after')
20+
this._value = ['', ' '];
21+
if (value.constructor === Array && value[0].match(/^[ \t]*$/) && value[1].match(/^[ \t]*$/))
1322
this._value = value;
23+
if (typeof value === 'string') {
24+
if (value.match(/^[ \t]*$/)) {
25+
this._value = ['', value];
26+
} else {
27+
var detectSpaces = value.match(/^(([ \t]*):)?([ \t]*)$/);
28+
if (detectSpaces) {
29+
if (detectSpaces[1]) {
30+
this._value = [detectSpaces[2], detectSpaces[3]];
31+
} else {
32+
this._value = ['', detectSpaces[3]];
33+
}
34+
}
35+
}
1436
}
37+
1538
if (!this._value) return;
1639
return this;
1740
},
@@ -22,20 +45,13 @@ module.exports = {
2245
* @param {node} node
2346
*/
2447
process: function(nodeType, node) {
25-
var detectSpaces = this._value.match(/(([ \t\n]*):)?([ \t\n]*)/);
2648
if (nodeType === 'property') {
2749
if (node[node.length - 1][0] === 's') node.pop();
28-
if (this._value === 'both' || this._value === 'before')
29-
node.push(['s', ' ']);
30-
if (detectSpaces && detectSpaces[1])
31-
node.push(['s', detectSpaces[2]]);
50+
if (this._value[0] !== '') node.push(['s', this._value[0]]);
3251
}
3352
if (nodeType === 'value') {
3453
if (node[0][0] === 's') node.shift();
35-
if (this._value === 'both' || this._value === 'after')
36-
node.unshift(['s', ' ']);
37-
if (detectSpaces)
38-
node.unshift(['s', detectSpaces[3]]);
54+
if (this._value[1] !== '') node.unshift(['s', this._value[1]]);
3955
}
4056
}
4157

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
module.exports = {
2+
3+
/**
4+
* Sets handler value.
5+
*
6+
* @param {String} value Option value
7+
* @returns {Object|undefined}
8+
*/
9+
setValue: function(value) {
10+
if (value === true) {
11+
this._value = value;
12+
return this;
13+
}
14+
},
15+
16+
/**
17+
* Remove rulesets with no declarations.
18+
*
19+
* @param {String} nodeType
20+
* @param {Array} nodeContent
21+
*/
22+
process: function(nodeType, nodeContent) {
23+
if (nodeType === 'stylesheet') {
24+
this._processStylesheetContent(nodeContent);
25+
}
26+
},
27+
28+
_processStylesheetContent: function(nodeContent) {
29+
this._removeEmptyRulesets(nodeContent);
30+
this._mergeAdjacentWhitespace(nodeContent);
31+
},
32+
33+
_removeEmptyRulesets: function(nodeContent) {
34+
var i = nodeContent.length;
35+
while (i--) {
36+
if (this._isRuleset(nodeContent[i]) && this._isEmptyRuleset(nodeContent[i])) {
37+
nodeContent.splice(i, 1);
38+
}
39+
}
40+
},
41+
42+
/**
43+
* Removing ruleset nodes from tree may result in two adjacent whitespace nodes which is not correct AST:
44+
* [space, ruleset, space] => [space, space]
45+
* To ensure correctness of further processing we should merge such nodes into one.
46+
* [space, space] => [space]
47+
*/
48+
_mergeAdjacentWhitespace: function(nodeContent) {
49+
var i = nodeContent.length - 1;
50+
while (i-- > 0) {
51+
if (this._isWhitespace(nodeContent[i]) && this._isWhitespace(nodeContent[i + 1])) {
52+
nodeContent[i][1] += nodeContent[i + 1][1];
53+
nodeContent.splice(i + 1, 1);
54+
}
55+
}
56+
},
57+
58+
_isEmptyRuleset: function(ruleset) {
59+
return ruleset.filter(this._isBlock).every(this._isEmptyBlock, this);
60+
},
61+
62+
/**
63+
* Block considered empty when it has no declarations or comments.
64+
*/
65+
_isEmptyBlock: function(node) {
66+
return !node.some(this._isDeclarationOrComment);
67+
},
68+
69+
_isDeclarationOrComment: function(node) {
70+
return node[0] === 'declaration' || node[0] === 'comment';
71+
},
72+
73+
_isRuleset: function(node) {
74+
return node[0] === 'ruleset';
75+
},
76+
77+
_isBlock: function(node) {
78+
return node[0] === 'block';
79+
},
80+
81+
_isWhitespace: function(node) {
82+
return node[0] === 's';
83+
}
84+
85+
};

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "csscomb",
33
"description": "CSS coding style formatter",
4-
"version": "0.0.14",
4+
"version": "0.0.15",
55
"homepage": "http://csscomb.com/",
66
"author": "Mikhail Troshev <mishanga@yandex-team.ru>",
77
"repository": "https://github.com/csscomb/csscomb.js",

test/colon-space.js

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,24 @@ describe('options/colon-space', function() {
3030
'a {color /* bar */: red }'
3131
);
3232
});
33-
it('`after` value should set space after colon', function() {
33+
it('False Boolean value should set no space around colon', function() {
34+
comb.configure({ 'colon-space': false });
35+
assert.equal(
36+
comb.processString(
37+
'a { color: red }' +
38+
'a{color:red}' +
39+
'a {color : red}' +
40+
'a {color : /* foo */ red }' +
41+
'a {color /* bar */ : red }'
42+
),
43+
'a { color:red }' +
44+
'a{color:red}' +
45+
'a {color:red}' +
46+
'a {color:/* foo */ red }' +
47+
'a {color /* bar */:red }'
48+
);
49+
});
50+
it('String `after` value should set space after colon', function() {
3451
comb.configure({ 'colon-space': 'after' });
3552
assert.equal(
3653
comb.processString(
@@ -47,7 +64,7 @@ describe('options/colon-space', function() {
4764
'a {color /* bar */: red }'
4865
);
4966
});
50-
it('`before` value should set space before colon', function() {
67+
it('String `before` value should set space before colon', function() {
5168
comb.configure({ 'colon-space': 'before' });
5269
assert.equal(
5370
comb.processString(
@@ -64,7 +81,7 @@ describe('options/colon-space', function() {
6481
'a {color /* bar */ :red }'
6582
);
6683
});
67-
it('`both` value should set spaces around colon', function() {
84+
it('String `both` value should set spaces around colon', function() {
6885
comb.configure({ 'colon-space': 'both' });
6986
assert.equal(
7087
comb.processString(
@@ -77,7 +94,7 @@ describe('options/colon-space', function() {
7794
'a {color : red}'
7895
);
7996
});
80-
it('` ` value should set two spaces after colon', function() {
97+
it('String ` ` value should set two spaces after colon', function() {
8198
comb.configure({ 'colon-space': ' ' });
8299
assert.equal(
83100
comb.processString(
@@ -90,7 +107,7 @@ describe('options/colon-space', function() {
90107
'a {color: red}'
91108
);
92109
});
93-
it('`:` value should set no space around colon', function() {
110+
it('String `:` value should set no space around colon', function() {
94111
comb.configure({ 'colon-space': ':' });
95112
assert.equal(
96113
comb.processString(
@@ -103,20 +120,20 @@ describe('options/colon-space', function() {
103120
'a {color:red}'
104121
);
105122
});
106-
it('`\\n:` value should set a newline before colon', function() {
107-
comb.configure({ 'colon-space': '\n:' });
123+
it('String `` value should set no space around colon', function() {
124+
comb.configure({ 'colon-space': '' });
108125
assert.equal(
109126
comb.processString(
110127
'a { color: red }' +
111128
'a{color:red}' +
112129
'a {color : red}'
113130
),
114-
'a { color\n:red }' +
115-
'a{color\n:red}' +
116-
'a {color\n:red}'
131+
'a { color:red }' +
132+
'a{color:red}' +
133+
'a {color:red}'
117134
);
118135
});
119-
it('`\\t:\\t` value should set tabs around colon', function() {
136+
it('String `\\t:\\t` value should set tabs around colon', function() {
120137
comb.configure({ 'colon-space': '\t:\t' });
121138
assert.equal(
122139
comb.processString(

0 commit comments

Comments
 (0)