Skip to content

Commit

Permalink
Merge pull request #49 from t32k/develop
Browse files Browse the repository at this point in the history
Support LESS/Stylus
  • Loading branch information
t32k committed Mar 27, 2014
2 parents ced2dd2 + 77757e3 commit c24afd3
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 44 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ _(Coming soon)_
## Release History
+ v3.1.0: Support compiled Less/Stylus files.
+ v3.0.0: __API is changed:__ CLI option. Support parse HTML page.
+ v2.3.0: Support HTML output CLI option.
+ v2.2.0: Add `dataUriSize`, `ratioOfDataUriSize` metics.
Expand Down
129 changes: 95 additions & 34 deletions lib/parser.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
var _ = require('underscore');
var fs = require('fs');
var url = require('url');
var path = require('path');
var Promise = require('promise');
var request = require('request');
var cheerio = require('cheerio');
var cssParse = require('css-parse');

var util = require('./util');

/**
* Get promised request
* @param {String} url
Expand Down Expand Up @@ -36,6 +39,27 @@ function Parser(urls, files, styles) {
this.urls = urls;
this.files = files;
this.styles = styles;

this.cssFiles = [];
this.sassFiles = [];
this.lessFiles = [];
this.stylusFiles = [];

this.files.forEach(function(file) {
var extname = path.extname(file);
switch (extname) {
case '.css':
this.cssFiles.push(file);
break;
case '.less':
this.lessFiles.push(file);
break;
case '.styl':
case '.stylus':
this.stylusFiles.push(file);
break;
}
}, this);
}

/**
Expand Down Expand Up @@ -66,51 +90,88 @@ Parser.prototype.parse = function(callback) {

// css string array from arguments
// they will be joined into css string
this.files.forEach(function(file) {
this.cssFiles.forEach(function(cssFile) {
// push local css data
that.styles.push(fs.readFileSync(file, {
that.styles.push(fs.readFileSync(cssFile, {
encoding: 'utf8'
}));
});
// LESS compile
if (this.lessFiles.length !== 0) {
var less = require('less');
this.lessFiles.forEach(function(lessFile) {
var parser = new(less.Parser)({
filename: lessFile
});
var promise = new Promise(function(resolve, reject) {
var string = fs.readFileSync(lessFile, 'utf8');
parser.parse(string, function(error, tree) {
if (error) {
reject(error);
}
resolve(tree.toCSS());
});
});
requestPromises.push(promise);
});
}
// Stylus compile
if (this.stylusFiles.length !== 0) {
var stylus = require('stylus');
this.stylusFiles.forEach(function(stylusFile) {
var promise = new Promise(function(resolve, reject) {
var string = fs.readFileSync(stylusFile, 'utf8');
stylus(string)
.set('filename', stylusFile)
.render(function(error, css) {
if (error) {
reject(error);
}
resolve(css);
});
});
requestPromises.push(promise);
});
}

// get remote files
Promise.all(requestPromises).then(function onFulfilled(responses) {
Promise.all(requestPromises).then(function onFulfilled(results) {

// requests to stylesheet defined in html
var requestPromisesInner = [];

// push remote css data
responses.forEach(function(response) {

// response content type
var contentType = response.headers['content-type'];

if (contentType.indexOf('html') > -1) {

// parse response body
var $ = cheerio.load(response.body);
var $link = $('link[rel=stylesheet]');
var $style = $('style');

// add css file count
result.cssFiles += $link.length;
result.styleElements += $style.length;

// request link[href]
$link.each(function() {
var relPath = $(this).attr('href');
var absPath = url.resolve(response.request.href, relPath);
requestPromisesInner.push(requestSync(absPath));
});

// add text in style tags
$style.each(function() {
that.styles.push($(this).text());
});
} else if (contentType.indexOf('css') > -1) {
that.styles.push(response.body);
results.forEach(function(result) {
if (util.isCSS(result)) {
that.styles.push(result);
} else {
throw new Error('Content type is not HTML or CSS!');
// push remote css data
var type = result.headers['content-type'];
if (type.indexOf('html') > -1) {
// parse result body
var $ = cheerio.load(result.body);
var $link = $('link[rel=stylesheet]');
var $style = $('style');

// add css file count
result.cssFiles += $link.length;
result.styleElements += $style.length;

// request link[href]
$link.each(function() {
var relPath = $(this).attr('href');
var absPath = url.resolve(result.request.href, relPath);
requestPromisesInner.push(requestSync(absPath));
});

// add text in style tags
$style.each(function() {
that.styles.push($(this).text());
});
} else if (type.indexOf('css') > -1) {
that.styles.push(result.body);
} else {
throw new Error('Content type is not HTML or CSS!');
}
}
});

Expand Down
8 changes: 5 additions & 3 deletions lib/stylestats.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,19 @@ function StyleStats(args, config) {
this.files = [];
this.styles = [];

var EXTENSIONS = ['.less', '.styl', '.stylus', '.css'];

// check arguments which is url or file path or other
args.forEach(function(arg) {
if (util.isFile(arg) && path.extname(arg) === '.css') {
if (util.isFile(arg) && EXTENSIONS.indexOf(path.extname(arg)) !== -1) {
that.files.push(arg);
} else if (util.isDirectory(arg)) {
fs.readdirSync(arg).filter(function(file) {
return (path.extname(file) === '.css');
return (EXTENSIONS.indexOf(path.extname(file)) !== -1);
}).forEach(function(file) {
that.files.push(arg + file);
});
} else if (URL.test(arg) && path.extname(arg).indexOf('.css') > -1) {
} else if (URL.test(arg) && path.extname(arg).indexOf('.css') !== -1) {
that.urls.push(arg);
} else if (URL.test(arg)) {
that.urls.push(arg);
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "stylestats",
"version": "3.0.2",
"version": "3.1.0",
"main": "lib/stylestats.js",
"bin": {
"stylestats": "bin/cli.js"
Expand Down Expand Up @@ -30,7 +30,7 @@
"property"
],
"scripts": {
"test": "mocha --timeout 5000 --reporter=spec"
"test": "mocha --timeout 10s --reporter=spec"
},
"engines": {
"node": "0.10.x"
Expand All @@ -43,6 +43,8 @@
"dependencies": {
"jade": "~1.3.0",
"glob": "~3.2.9",
"less": "~1.7.0",
"stylus": "~0.42.3",
"numeral": "~1.5.3",
"promise": "~4.0.0",
"cheerio": "~0.13.1",
Expand Down
3 changes: 3 additions & 0 deletions test/fixture/prepros/bar.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.bar {
color: red
}
2 changes: 2 additions & 0 deletions test/fixture/prepros/bar.styl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.bar
font font-size Arial, sans-serif
44 changes: 44 additions & 0 deletions test/fixture/prepros/foo.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
@import "bar.less";

// Variables
@nice-blue: #5B83AD;
@light-blue: @nice-blue + #111;

#header {
color: @light-blue;
}

// Mixins
.bordered {
border-top: dotted 1px black;
border-bottom: solid 2px black;
}
#menu a {
color: #111;
.bordered;
}
.post a {
color: red;
.bordered;
}

// Nested rules
#header {
color: black;
.navigation {
font-size: 12px;
}
.logo {
width: 300px;
}
}

// Functions
@base: #f04615;
@width: 0.5;

.class {
width: percentage(@width); // returns `50%`
color: saturate(@base, 5%);
background-color: spin(lighten(@base, 25%), 8);
}
28 changes: 28 additions & 0 deletions test/fixture/prepros/foo.styl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
@import 'bar'

// Variables
font-size = 14px

body
font font-size Arial, sans-serif

// Mixins
border-radius(n)
-webkit-border-radius n
-moz-border-radius n
border-radius n

form input[type=button]
border-radius(5px)

// Functions
add(a, b)
a + b

body
padding add(10px, 5)

// Iteration
body
for num in 1 2 3
foo num
31 changes: 26 additions & 5 deletions test/stats-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@ describe('Analyze remote css file', function() {
});
});

describe('Analyze HTML pages', function() {
it('should return the number of stylesheets', function(done) {
var htmlStats = new StyleStats('http://t32k.me/');
htmlStats.parse(function(htmlResult) {
assert.equal(htmlResult.size, 15419);
done();
});
});
});

describe('Analyze files of specified directory', function() {
it('should return file size', function(done) {
var dirStats = new StyleStats('test/fixture/');
Expand Down Expand Up @@ -152,11 +162,22 @@ describe('Analyze raw contents files', function() {
});
});

describe('Analyze HTML pages', function() {
it('should return the number of stylesheets', function(done) {
var htmlStats = new StyleStats('https://dl.dropboxusercontent.com/u/356242/test/stats/async.html');
htmlStats.parse(function(htmlResult) {
assert.equal(htmlResult.size, 508);

describe('Analyze LESS files', function() {
it('should return file size', function(done) {
var lessStats = new StyleStats('test/fixture/prepros/foo.less');
lessStats.parse(function(lessResult) {
assert.equal(lessResult.size, 499);
done();
});
});
});

describe('Analyze Stylus files', function() {
it('should return file size', function(done) {
var stylStats = new StyleStats('test/fixture/prepros/foo.styl');
stylStats.parse(function(stylResult) {
assert.equal(stylResult.size, 259);
done();
});
});
Expand Down

0 comments on commit c24afd3

Please sign in to comment.