Skip to content

Commit

Permalink
Merge b3a5c2e into 7fb2471
Browse files Browse the repository at this point in the history
  • Loading branch information
Shogo Sensui committed Mar 25, 2014
2 parents 7fb2471 + b3a5c2e commit 90f9d72
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 23 deletions.
29 changes: 24 additions & 5 deletions README.md
@@ -1,6 +1,6 @@
![StyleStats](http://i.imgur.com/81kKnxH.png)

StyleStats is Node.js library to collect css statistics.
StyleStats is Node.js library to collect CSS statistics.

[![Build Status](https://secure.travis-ci.org/t32k/stylestats.png?branch=master)](http://travis-ci.org/t32k/stylestats)
[![Coverage Status](https://coveralls.io/repos/t32k/stylestats/badge.png)](https://coveralls.io/r/t32k/stylestats)
Expand Down Expand Up @@ -89,11 +89,29 @@ StyleStats supports multiple input.
```sh
$ stylestats foo.css bar.css baz.css
```
supports directory input.

`-e` option output JSON or CSV.
```sh
$ stylestats path/to/dir
```

supports glob(required quotations) input.

```sh
$ stylestats 'path/**/*.css'
```

`-e` option output JSON or CSV or HTML.

```sh
$ stylestats foo.css -e [json|csv|html]
```

If you installed __[gist](https://github.com/defunkt/gist)__ tool, you can upload StyleStats data to [GitHub Gist](https://gist.github.com/9725673) with one-liner command.

```sh
$ stylestats foo.css -e [json|csv]
$ stylestats http://t32k.me/static/blog/skelton.css -e html > stats.md && gist stats.md
https://gist.github.com/9725673
```

## Grunt & Gulp modules
Expand Down Expand Up @@ -256,6 +274,8 @@ Statistics tree of above css:
```json
{
"published": "2014-03-23T15:54:39.825Z",
"paths": [ "test/fixture/example.css" ],
"stylesheets": 1,
"size": 240,
"dataUriSize": 0,
Expand Down Expand Up @@ -293,6 +313,7 @@ _(Coming soon)_
## Release History
+ v2.3.0: Support HTML output CLI option.
+ v2.2.0: Add `dataUriSize`, `raitoOfDataUriSize` metics.
+ v2.1.0: Add `javascriptSpecificSelectors` metics, and fix counting properties in mediaQueries.
+ v2.0.0: __API is changed:__ `StyleStats.parse()`. Add metrics.
Expand All @@ -303,5 +324,3 @@ _(Coming soon)_
# License
Code is released under [the MIT license](LICENSE).
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/t32k/stylestats/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
43 changes: 40 additions & 3 deletions lib/analyzer.js
Expand Up @@ -3,9 +3,12 @@ var gzipSize = require('gzip-size');

/**
* Analyzer class
* @param rules
* @param selectors
* @param declarations
* @param {Array} rules
* @param {Array} selectors
* @param {Array} declarations
* @param {String} cssString
* @param {Number} cssSize
* @param {Object} options
* @constructor
*/
function Analyzer(rules, selectors, declarations, cssString, cssSize, options) {
Expand Down Expand Up @@ -39,9 +42,13 @@ function Analyzer(rules, selectors, declarations, cssString, cssSize, options) {
* }
*/
Analyzer.prototype.analyzeRules = function () {

// object to return
var result = {
cssDeclarations: []
};

// analyze rules
this.rules.forEach(function(rule) {
if (Array.isArray(rule.declarations)) {
result.cssDeclarations.push({
Expand All @@ -50,9 +57,12 @@ Analyzer.prototype.analyzeRules = function () {
});
}
});

// sort by css declaration count
result.cssDeclarations.sort(function decreasingOrder(a, b) {
return b.count - a.count;
});

return result;
};

Expand Down Expand Up @@ -82,18 +92,28 @@ Analyzer.prototype.analyzeSelectors = function () {

// analyze selectors
this.selectors.forEach(function(selector) {

// if it contains #
if (selector.indexOf('#') > -1) {
result.idSelectors += 1;
}

// if it contains *
if (selector.indexOf('*') > -1) {
result.universalSelectors += 1;
}

// if it is unqualified attribute selector
if (selector.trim().match(/\[.+\]$/g)) {
result.unqualifiedAttributeSelectors += 1;
}

// if it is for JavaScript hook
if (regexp.test(selector.trim())) {
result.javascriptSpecificSelectors += 1;
}

// add selector for statistics
var trimmedSelector = selector.replace(/\s?([\>|\+|\~])\s?/g, '$1');
trimmedSelector = trimmedSelector.replace(/\s+/g, ' ');
var count = trimmedSelector.split(/\s|\>|\+|\~/).length;
Expand All @@ -102,9 +122,12 @@ Analyzer.prototype.analyzeSelectors = function () {
count: count
});
});

// sort by chained selector count
result.identifiers.sort(function decreasingOrder(a, b) {
return b.count - a.count;
});

return result;
};

Expand Down Expand Up @@ -133,23 +156,35 @@ Analyzer.prototype.analyzeDeclarations = function () {

// analyze declarations
this.declarations.forEach(function(declaration) {

// if it contains DataURI
if (declaration.value.indexOf('data:image') > -1) {
result.dataUriSize += declaration.value.match(/data\:image\/[A-Za-z0-9;,\+\=\/]+/);
}

// if it contains !important keyword
if (declaration.value.indexOf('!important') > -1) {
result.importantKeywords += 1;
}

// if it contains float
if (declaration.property.indexOf('float') > -1) {
result.floatProperties += 1;
}

// if it contains font-size
if (declaration.property.indexOf('font-size') > -1) {
result.uniqueFontSize.push(declaration.value.replace(/\!important/, '').trim());
}

// if it contains colors
if (declaration.property.match(/^color$/)) {
var color = declaration.value.replace(/\!important/, '');
color = color.toUpperCase().trim();
result.uniqueColor.push(color);
}

// property statistics
if (result.properties[declaration.property]) {
result.properties[declaration.property] += 1;
} else {
Expand All @@ -176,6 +211,8 @@ Analyzer.prototype.analyzeDeclarations = function () {
count: result.properties[key]
});
});

// sort by property count
result.properties = propertiesCount.sort(function decreasingOrder(a, b) {
return b.count - a.count;
});
Expand Down
33 changes: 26 additions & 7 deletions lib/parser.js
Expand Up @@ -5,9 +5,10 @@ var Promise = require('promise');
var cssParse = require('css-parse');
var request = require('request');


/**
* get promised request
* @param url
* Get promised request
* @param {String} url
* @returns {Promise}
*/
function requestSync(url) {
Expand All @@ -33,13 +34,24 @@ function requestSync(url) {
function Parser(urls, files) {
this.urls = urls;
this.files = files;
this.styles = [];
}

/**
* Add css string
* @param {String} style
*/
Parser.prototype.addString = function (style) {
this.styles.push(style);
};

/**
* Parse css data
* @param callback
* @param {Function} callback
*/
Parser.prototype.parse = function (callback) {

// object to return
var result = {
cssString: '',
cssSize: 0,
Expand All @@ -49,6 +61,8 @@ Parser.prototype.parse = function (callback) {
declarations: []
};

var that = this;

// remote file requests
var requestPromises = [];
this.urls.forEach(function(url) {
Expand All @@ -57,24 +71,27 @@ Parser.prototype.parse = function (callback) {

// css string array from arguments
// they will be joined into css string
var styles = [];
this.files.forEach(function(file) {
// push local css data
styles.push(fs.readFileSync(file, {
that.styles.push(fs.readFileSync(file, {
encoding: "utf-8"
}));
});

// get remote files
Promise.all(requestPromises).done(function onFulfilled(value) {

// push remote css data
styles.push(value.join(''));
that.styles.push(value.join(''));

// join all css string
result.cssString = styles.join('');
result.cssString = that.styles.join('');
result.cssSize = Buffer.byteLength(result.cssString, 'utf8');

// parse css string
var rawRules = cssParse(result.cssString).stylesheet.rules;

// add rules into result
rawRules.forEach(function(rule) {
if (rule.type === 'rule') {
result.rules.push(rule);
Expand All @@ -88,6 +105,7 @@ Parser.prototype.parse = function (callback) {
}
});

// add selectors and declarations into result
result.rules.forEach(function(rule) {
rule.selectors.forEach(function(selector) {
result.selectors.push(selector);
Expand All @@ -109,4 +127,5 @@ Parser.prototype.parse = function (callback) {
});
};

// export
module.exports = Parser;
8 changes: 4 additions & 4 deletions lib/stylestats.js
Expand Up @@ -19,8 +19,8 @@ var Analyzer = require('./analyzer');

/**
* StyleStats class
* @param args
* @param config
* @param {Array} args
* @param {String|Object} config
* @constructor
*/
function StyleStats(args, config) {
Expand Down Expand Up @@ -53,8 +53,6 @@ function StyleStats(args, config) {
});
}
});

this.parser = new Parser(this.urls, this.files);

var defaultOptions = require('./default.json');
var customOptions = {};
Expand All @@ -70,7 +68,9 @@ function StyleStats(args, config) {
} else if (_.isObject(config)) {
customOptions = config;
}

this.options = _.extend({}, defaultOptions, customOptions);
this.parser = new Parser(this.urls, this.files);
}

/**
Expand Down
8 changes: 8 additions & 0 deletions lib/util.js
@@ -1,6 +1,10 @@
var fs = require('fs');
var path = require('path');

/**
* Argument is file path or not
* @returns {Boolean}
*/
function isFile() {
try {
var file = path.join.apply(path, arguments);
Expand All @@ -10,6 +14,10 @@ function isFile() {
}
}

/**
* Argument is directory path or not
* @returns {Boolean}
*/
function isDirectory() {
try {
var dir = path.join.apply(path, arguments);
Expand Down
8 changes: 4 additions & 4 deletions package.json
@@ -1,11 +1,11 @@
{
"name": "stylestats",
"version": "2.2.1",
"version": "2.3.0",
"main": "lib/stylestats.js",
"bin": {
"stylestats": "./bin/stylestats"
},
"description": "StyleStats is Node.js library to collect css statistics!",
"description": "StyleStats is Node.js library to collect CSS statistics!",
"homepage": "https://github.com/t32k/stylestats",
"bugs": "https://github.com/t32k/stylestats/issues",
"author": {
Expand Down Expand Up @@ -40,6 +40,7 @@
"bin"
],
"dependencies": {
"jade": "~1.3.0",
"glob": "~3.2.9",
"numeral": "~1.5.3",
"promise": "~4.0.0",
Expand All @@ -50,8 +51,7 @@
"cli-table": "~0.3.0",
"gzip-size": "~0.1.0",
"underscore": "~1.6.0",
"underscore.string": "~2.3.3",
"jade": "~1.3.0"
"underscore.string": "~2.3.3"
},
"devDependencies": {
"mocha": "~1.17.1",
Expand Down

0 comments on commit 90f9d72

Please sign in to comment.