Skip to content
This repository was archived by the owner on Jan 27, 2019. It is now read-only.
Merged

V2 #42

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
4b433a0
Rename results
jxnblk Jul 28, 2015
78204d5
Rename src
jxnblk Jul 28, 2015
70bd0bd
Rename opts
jxnblk Jul 28, 2015
3452aa4
Add lite option
jxnblk Jul 28, 2015
355c952
Handle default behavior or use as a PostCSS plugin
jxnblk Jul 28, 2015
b4d98d6
Update selectors module
jxnblk Jul 28, 2015
a2a4edd
Adjust rules module
jxnblk Jul 28, 2015
0daf9b1
Simplify declarations
jxnblk Jul 28, 2015
1e2448d
Comment out lite option
jxnblk Jul 28, 2015
74280ee
Count total declarations
jxnblk Jul 28, 2015
b9d5d10
Update tests
jxnblk Jul 28, 2015
44f78ae
Use reduce for finding duplicate selectors
jxnblk Jul 28, 2015
b1fa8b9
Add media queries module
jxnblk Jul 28, 2015
018399b
Add standard
jxnblk Jul 28, 2015
ae017ec
Use standard
jxnblk Jul 28, 2015
3a78964
Remove unused aggregates object
jxnblk Jul 28, 2015
c5c3811
Remove unused modules
jxnblk Jul 28, 2015
48e368f
Update README
jxnblk Jul 28, 2015
e3af577
Add usage examples section to readme
jxnblk Jul 28, 2015
64446fd
Add all stats for each media query
jxnblk Jul 28, 2015
cd0add7
Pass opts to each module
jxnblk Jul 28, 2015
5669b5e
First pass at lite option
jxnblk Jul 28, 2015
985653a
Push media query contents to an array
jxnblk Jul 29, 2015
9237f87
Specificity graph method
jxnblk Jul 29, 2015
376b6c6
Get repeated selectors method
jxnblk Jul 29, 2015
1b7320a
Get property resets method
jxnblk Jul 29, 2015
3cd6e07
Add mediaQueries option
jxnblk Jul 29, 2015
2e7650e
Add property methods
jxnblk Jul 29, 2015
fdf4ee4
Add sorted specificity method
jxnblk Jul 29, 2015
19c4f1c
Update readme
jxnblk Jul 29, 2015
5ecdf3f
Add methods to object in readme
jxnblk Jul 29, 2015
aca2e17
Add options for methods
jxnblk Jul 29, 2015
a77b8ad
Add vendor prefix method
jxnblk Jul 29, 2015
13cb0a1
Add optional array of important declarations
jxnblk Jul 29, 2015
bd7f4a3
Remove method from json
jxnblk Jul 29, 2015
a52b87e
Add font size and font family methods
jxnblk Jul 29, 2015
86ade75
Type selectors count
jxnblk Jul 29, 2015
6372393
Use css-selector-tokenizer
jxnblk Jul 29, 2015
4bf0deb
2.0.0-beta.1
jxnblk Jul 30, 2015
cc04080
Move specificity graph generation out of loop
jxnblk Jul 31, 2015
3d64c09
2.0.0-beta.2
jxnblk Jul 31, 2015
d128dca
Adjust specificity graph
jxnblk Jul 31, 2015
5e82d58
2.0.0-beta.3
jxnblk Jul 31, 2015
00a9c1a
Provide parent argument for parsing font sizes
jxnblk Aug 5, 2015
a2a421e
Remove lite option
jxnblk Aug 5, 2015
13bb1c6
Count max rule size
jxnblk Aug 5, 2015
bcc2038
Change order of selectors object
jxnblk Aug 5, 2015
8242673
Update tests
jxnblk Aug 5, 2015
3076b99
Fix non-standard issues
jxnblk Aug 5, 2015
e437723
2.0.0-beta.4
jxnblk Aug 5, 2015
469fcb5
Fix typo
jxnblk Aug 5, 2015
06e59b7
Edit readme
jxnblk Aug 5, 2015
e9d8a43
Edit title for readme
jxnblk Aug 5, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@


// Personal styling preferences.
"asi" : true,
"newcap" : true, // Require capitalization of all constructor functions e.g. `new F()`.
"noempty" : true, // Prohibit use of empty blocks.
"nomen" : true, // Prohibit use of initial or trailing underbars in names.
Expand Down
251 changes: 208 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,48 @@
# CSS Statistics
# cssstats
Parses stylesheets and returns an object with statistics

Used in http://cssstats.com
This is the core module used in http://cssstats.com

## Installation

```sh
npm install --save cssstats
npm install cssstats
```

## Usage

### Node

```js
var fs = require('fs');
var cssstats = require('csstats');
var fs = require('fs')
var cssstats = require('csstats')

var css = fs.readFileSync('./styles.css', 'utf8');
var obj = cssstats(css);
var css = fs.readFileSync('./styles.css', 'utf8')
var stats = cssstats(css)
```

Instead of a CSS string, you can also pass the [PostCSS AST](https://github.com/postcss/postcss):
### PostCSS Plugin

```js
var fs = require('fs');
var postcss = require('postcss');
var cssstats = require('csstats');
CSS Stats can be used as a [PostCSS](https://github.com/postcss/postcss) plugin.
The stats will be added to PostCSS's messages array.

var css = fs.readFileSync('./styles.css', 'utf8');
var ast = postcss.parse(css);
var obj = cssstats(ast);
```js
var fs = require('fs')
var postcss = require('postcss')
var cssstats = require('csstats')

var css = fs.readFileSync('./styles.css', 'utf8')
postcss()
.use(cssstats())
.process(css)
.then(function (result) {
result.messages.forEach(function (message) {
console.log(message)
})
})
```

### Using the CLI
#### CLI

```sh
npm i -g cssstats
Expand All @@ -45,41 +56,195 @@ cat some-css-file.css | cssstats
getcss google.com | cssstats
```

#### Options

Options may be passed as a second argument.

```js
var stats = cssstats(css, { mediaQueries: false })
```

- `safe` (boolean, default: `true`) - enables [PostCSS safe mode](https://github.com/postcss/postcss#safe-mode) for parsing CSS with syntax errors
- `mediaQueries` (boolean, default `true`) - determines whether or not to generate stats for each media query block
- `importantDeclarations` (boolean, default `false`) - include an array of declarations with `!important`

The following options add the results of helper methods to the returned object. This is helpful when using `JSON.stringify()`.

- `specificityGraph` (boolean, deault `false`)
- `sortedSpecificityGraph` (boolean, deault `false`)
- `repeatedSelectors` (boolean, deault `false`)
- `propertyResets` (boolean, deault `false`)
- `vendorPrefixedProperties` (boolean, deault `false`)

### Returned Object

__`size`:__ The size of the file in bytes
```js
// Example
{
size: n,
gzipSize: n,
rules: {
total: n,
size: {
graph: [n],
max: n,
average: n
}
},
selectors: {
total: n,
id: n,
class: n,
type: n,
pseudoClass: n,
psuedoElement: n,
values: [str],
specificity: {
max: n
average: n
},
getSpecificityGraph(),
getRepeatedValues(),
getSortedSpecificity()
},
declarations: {
total: n,
important: n,
properties:
prop: [str]
},
getPropertyResets(),
getUniquePropertyCount(),
getPropertyValueCount(),
getVendorPrefixed(),
getAllFontSizes(),
getAllFontFamilies(),
},
mediaQueries: {
total: n,
unique: n,
values: [str],
contents: [
{
value: str,
rules: {
total: n,
size: {
graph: [n],
max: n,
average: n
}
},
selectors: {
total: n,
id: n,
class: n,
type: n,
pseudoClass: n,
pseudoElement: n,
values: [str],
specificity: {
max: n,
average: n
}
},
declarations: {
total: n,
important: n,
vendorPrefix: n,
properties: {
prop: [str]
}
}
}
]
}
}
```

#### `size` number
The size of the file in bytes

#### `gzipSize` number
The size of the stylesheet gzipped in bytes

__`gzipSize`:__ The size of the stylesheet gzipped in bytes
#### `rules` object

__`selectors`:__ An array of selectors sorted by source order with the selector string, specificity score, and parts array
- `total` number - total number of rules
- `size` object
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

- object

Edit: Nevermind, I see the pattern here : )

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any advice on a standard way of writing this out would be cool. I don't know if using something like jsdoc is still cool.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the current formatting. Though, I'd probably prefer to see the type for all properties: number, object, array, etc. IMO it's pretty useful when scanning the API docs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, I'll add those in. Related: does that weird fence block with the returned object make sense or is there a better way to represent that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made sense to me.

- `size.graph` array - ruleset sizes (number of declarations per rule) in source order
- `size.max` number - maximum ruleset size
- `size.average` number - average ruleset size

__`declarations`:__ An object of declarations.
- `declarations.all`: An array of declaration objects from PostCSS.
- `declarations.byProperty`: An object with keys for each property found in the stylesheet.
- `declarations.unique`: An object with keys for each unique property/value found in the stylesheet.
- `declarations.byMedia`: An object with keys for each media query found in the stylesheet.
- `declarations.propertyResetDeclarations`: An object with keys for each property with a value of `0` found in the stylesheet. (Actually only margins and paddings are counted)
- `declarations.importantCount`: The number of declarations with values that contain `!important`
- `declarations.vendorPrefixCount`: The number of declaration properties that have vendor prefixes.
- `declarations.displayNoneCount`: The number of `display: none;` declarations.
- `declarations.uniqueDeclarationsCount`: The number of unique declarations.
#### `selectors` object

__`rules`:__ Flattened array of rules from PostCSS.
- `total` number - total number of selectors
- `type` number - total number of type selectors
- `class` number - total number of class selectors
- `id` number - total number of id selectors
- `pseudoClass` number - total number of pseudo class selectors
- `pseudoElement` number - total number of pseudo element selectors
- `values` array - array of strings for all selectors
- `specificity` object
- `specificity.max` number - maximum specificity as a base 10 number
- `specificity.average` number - average specificity as a base 10 number
- `getSpecificityGraph()` function - returns an array of numbers for each selector’s specificity as a base 10 number
- `getRepeatedValues()` function - returns an array of strings of repeated selectors
- `getSortedSpecificity()` function - returns an array of selectors with base 10 specificity score, sorted from highest to lowest

__`aggregates`:__ Aggregate data for the entire stylesheet.
- `selectors` - total number of selectors
- `declarations` - total number of declarations
- `properties` - an array of properties used in the stylesheet
- `mediaQueries` - an array of media query strings used in the stylesheet
- `idSelectors` - total number of selectors containing an id
- `classSelectors` - total number of selectors containing a class
- `pseudoElementSelectors` - total number of selectors containing an pseudo element
- `pseudoClassSelectors` - total number of selectors containing a pseudo class
- `repeatedSelectors` - array of selectors that were declared more than once
#### `declarations` object

For every unique property found in the stylesheet, `aggregates` also includes these values:
- `[property].total` - total number of [property] declarations
- `[property].unique` - number of unique [property] declarations
- `total` number - total number of declarations
- `properties` object - object with each unique property and an array of that property’s values
- `getPropertyResets()` function - returns an object with the number of times margin or padding is reset for each property
- `getUniquePropertyCount(property)` function - returns the number of unique values for the given property
- `getPropertyValueCount(property, value)` function - returns the number of times a declaration occurs for the given property and value
- `getVendorPrefixed()` function - returns an array of declarations with vendor prefixed properties
- `getAllFontSizes()` function - returns an array of font sizes from both `font-size` and `font` shorthand declarations
- `getAllFontFamilies()` function - returns an array of font families from both `font-family` and `font` shorthand declarations
- `important` array (optional) - `!important` declaration objects with `property` and `value`

#### `mediaQueries` object

- `total` number - total number of media queries
- `unique` number - total unique media queries
- `values` array - array of values for each media query
- `contents` array - array of media query blocks with full stats object for each


See the `/test/results` folder for example JSON results.

### Usage examples

```js
var cssstats = require('cssstats')
var stats = cssstats(css)
```

#### Generate a [specificity graph](http://csswizardry.com/2014/10/the-specificity-graph/)

```js
var specificityGraph = stats.selectors.getSpecificityGraph()
```

#### Sort selectors by highest specificity

```js
var sortedSelectors = stats.selectors.getSortedSpecificity()
```

#### Get total number of unique colors

```js
var uniqueColorsCount = stats.declarations.getUniquePropertyCount('color')
```

#### `display: none` count

```js
var displayNoneCount = stats.declarations.getPropertyValueCount('display', 'none')
```


MIT License

38 changes: 19 additions & 19 deletions bin/cssstats.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
#!/usr/bin/env node

var program = require('commander');
var cssstats = require('..');
var fs = require('fs');
var stdin = require('stdin');
var program = require('commander')
var cssstats = require('..')
var fs = require('fs')
var stdin = require('stdin')

var version = '1.6.0'

console.log('CSS Statistics CLI (' + version + ')');
console.log('CSS Statistics CLI (' + version + ')')

program
.version(version);
.version(version)

program
.command('file [file]')
.description('read a local css file')
.action(function(file) {
.action(function (file) {
if (!file) {
console.log('Please specify a CSS file');
return;
console.log('Please specify a CSS file')
return
}

try {
var css = fs.readFileSync(file, 'utf8');
console.log(JSON.stringify(cssstats(css), null, 2));
var css = fs.readFileSync(file, 'utf8')
console.log(JSON.stringify(cssstats(css), null, 2))
} catch (e) {
console.log('CSS Statistics encountered an error reading ' + file);
console.log(e);
console.log('CSS Statistics encountered an error reading ' + file)
console.log(e)
}
});
})

program.parse(process.argv);
program.parse(process.argv)

if (!program.args.length) {
console.log('Input some CSS\n^C to cancel\n^D when complete');
console.log('Input some CSS\n^C to cancel\n^D when complete')

stdin(function(css) {
stdin(function (css) {
if (css) {
console.log(JSON.stringify(cssstats(css), null, 2));
console.log(JSON.stringify(cssstats(css), null, 2))
}
});
})
}
Loading