Skip to content

Commit 1edba4f

Browse files
committed
Merge pull request #6 from csscomb/v0.0.0
Allow to require and apply rules
2 parents c366ccb + c90733e commit 1edba4f

File tree

5 files changed

+205
-12
lines changed

5 files changed

+205
-12
lines changed

.csscomb.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
{
2+
"exclude": [
3+
".git/**",
4+
"node_modules/**"
5+
],
26
"colon-space": true,
37
"rule-indent": true,
48
"stick-brace": "\n",
9+
"strip-spaces": true,
510
"sort-order": [
611
[
712
"position",

.jscs.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"return",
1818
"catch"
1919
],
20-
"requireMultipleVarDecl": true,
20+
"disallowMultipleVarDecl": true,
2121
"disallowLeftStickedOperators": [
2222
"?",
2323
"+",

lib/cli.js

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,31 @@
44
* Usage example:
55
* ./node_modules/.bin/csscomb file1 [dir1 [fileN [dirN]]]
66
*/
7-
var fs = require('fs'),
8-
program = require('commander');
7+
var fs = require('fs');
8+
var program = require('commander');
9+
var vow = require('vow');
10+
var Comb = require('./csscomb');
911

1012
program
1113
.version(require('../package.json').version)
1214
.usage('[options] <file ...>')
1315
.option('-c, --config [path]', 'configuration file path')
1416
.parse(process.argv);
1517

18+
var comb = new Comb();
1619
var configPath = program.config || (process.cwd() + '/.csscomb.json');
1720

18-
/**
19-
* Trying to load config.
20-
* Custom config path can be specified using '-c' option.
21-
*/
2221
if (fs.existsSync(configPath)) {
23-
var config = require(configPath);
22+
comb.configure(require(configPath));
23+
if (program.args.length > 0) {
24+
vow.all(program.args.map(function(path) {
25+
return comb.processPath(path);
26+
})).fail(function(e) {
27+
console.log('stack: ', e.stack);
28+
process.exit(1);
29+
});
30+
}
2431
} else {
2532
console.log('Configuration file ' + configPath + ' was not found.');
26-
/**
27-
* Quitting with 1 error code.
28-
*/
2933
process.exit(1);
3034
}

lib/csscomb.js

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
var cssp = require('cssp');
2+
var minimatch = require('minimatch');
3+
var vow = require('vow');
4+
var vfs = require('vow-fs');
5+
6+
/**
7+
* Starts Code Style processing process.
8+
*
9+
* @name Comb
10+
*/
11+
var Comb = function() {
12+
this._rules = {
13+
'colon-space': {},
14+
'rule-indent': {},
15+
'sort-order': {},
16+
'stick-brace': {},
17+
'strip-spaces': {}
18+
},
19+
this._config = {};
20+
this._exclude = null;
21+
};
22+
23+
Comb.prototype = {
24+
25+
/**
26+
* Loads configuration from JSON.
27+
* Activates and configures required rules.
28+
*
29+
* @param {Object} config
30+
*/
31+
configure: function(config) {
32+
for (var rule in config) {
33+
if (config.hasOwnProperty(rule) && config[rule] && this._rules[rule]) {
34+
var beautifier;
35+
try {
36+
beautifier = require('./rules/' + rule);
37+
beautifier.value = config[rule];
38+
this._config[rule] = beautifier;
39+
} catch (e) {}
40+
}
41+
}
42+
this._exclude = (config.exclude || []).map(function(pattern) {
43+
return new minimatch.Minimatch(pattern);
44+
});
45+
},
46+
47+
/**
48+
* Processes stylesheet tree node.
49+
*
50+
* @param {Array} tree Parsed tree
51+
* @returns {Array}
52+
*/
53+
processTree: function(tree) {
54+
this.processNode(['tree', tree]);
55+
return tree;
56+
},
57+
58+
/**
59+
* Processes tree node.
60+
* @param {Array} node Tree node
61+
*/
62+
processNode: function(node, level) {
63+
var _this = this;
64+
var config = this._config;
65+
node.forEach(function(node) {
66+
if (!Array.isArray(node)) return;
67+
var nodeType = node.shift();
68+
for (var rule in config) {
69+
if (config.hasOwnProperty(rule)) {
70+
config[rule].process(nodeType, node);
71+
}
72+
}
73+
node.unshift(nodeType);
74+
_this.processNode(node, level);
75+
});
76+
},
77+
78+
/**
79+
* Process file provided with a string.
80+
* @param {String} text
81+
* @param {String} filename
82+
*/
83+
processString: function(text, filename) {
84+
var tree;
85+
try {
86+
tree = this.processTree(cssp.parse(text));
87+
} catch (e) {
88+
throw new Error('Parsing error at ' + filename + ': ' + e.message);
89+
}
90+
return cssp.translate(cssp.transform(tree));
91+
},
92+
93+
/**
94+
* Process single file.
95+
*
96+
* @param {String} path
97+
* @returns {Promise}
98+
*/
99+
processFile: function(path) {
100+
var _this = this;
101+
if (this._shouldProcess(path) && path.match(/\.css$/)) {
102+
return vfs.read(path, 'utf8').then(function(data) {
103+
return vfs.write(path, _this.processString(data, path), 'utf8');
104+
});
105+
}
106+
return null;
107+
},
108+
109+
/**
110+
* Process directory recursively.
111+
*
112+
* @param {String} path
113+
* @returns {Promise}
114+
*/
115+
processDirectory: function(path) {
116+
var _this = this;
117+
return vfs.listDir(path).then(function(filenames) {
118+
return vow.all(filenames.map(function(filename) {
119+
var fullname = path + '/' + filename;
120+
return vfs.stat(fullname).then(function(stat) {
121+
if (_this._shouldProcess(fullname)) {
122+
if (stat.isDirectory()) {
123+
return _this.processDirectory(fullname);
124+
} else if (fullname.match(/\.css$/)) {
125+
return vow.when(_this.processFile(fullname)).then(function(errors) {
126+
if (errors) return errors;
127+
});
128+
}
129+
}
130+
return;
131+
});
132+
})).then(function(results) {
133+
return [].concat.apply([], results);
134+
});
135+
});
136+
},
137+
138+
/**
139+
* Processs directory or file.
140+
*
141+
* @param {String} path
142+
*/
143+
processPath: function(path) {
144+
path = path.replace(/\/$/, '');
145+
var _this = this;
146+
return vfs.exists(path).then(function(exists) {
147+
if (exists) {
148+
return vfs.stat(path).then(function(stat) {
149+
if (stat.isDirectory()) {
150+
return _this.processDirectory(path);
151+
} else {
152+
return vow.when(_this.processFile(path)).then(function(errors) {
153+
if (errors) return [errors];
154+
return;
155+
});
156+
}
157+
});
158+
} else {
159+
throw new Error('Path ' + path + ' was not found.');
160+
}
161+
});
162+
},
163+
164+
/**
165+
* Returns true if specified path is not in exluded list.
166+
*
167+
* @returns {Boolean}
168+
*/
169+
_shouldProcess: function(path) {
170+
path = path.replace(/^\.\//, '');
171+
var exclude = this._exclude;
172+
for (var i = exclude.length; i--;) {
173+
if (exclude[i].match(path)) return false;
174+
}
175+
return true;
176+
}
177+
178+
};
179+
180+
module.exports = Comb;

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@
2121
"node": ">= 0.8.0"
2222
},
2323
"dependencies": {
24-
"commander": "1.1.1"
24+
"commander": "1.1.1",
25+
"cssp": "1.0.6",
26+
"minimatch": "0.2.12",
27+
"vow": "0.3.7",
28+
"vow-fs": "0.1.13"
2529
},
2630
"devDependencies": {
2731
"jshint-groups": "0.5.1",

0 commit comments

Comments
 (0)