list-selectors
What do you want in life? Is it to generate a nicely organized list of all the selectors used in your CSS, showing
- all the unique selectors used anywhere, in alphabetical order;
- all the unique simple selectors extracted from those sequences, in alphabetical order;
- those unique simple selectors broken out into id, class, attribute, and type selector categories (also alphabetical)?
Yes, that is probably what you want. And your dreams have been realized: this plugin does those things!
It can be used as a standalone Node function, a CLI, or a PostCSS plugin — so it's bound to fit into your workflow.
Installation
npm install list-selectors
What it Does
While PostCSS parses the input stylesheet(s), list-selectors
aggregates a list of all the selectors used. Then it alphabetizes them, extracts the simple selectors, sorts and categorizes those, and spits out an object — with which you can do what you will (some ideas below).
Here's an example input-output, explaining each part of the output object:
.fulvous { color: blue; }
#orotund { color: red; }
.Luddite { color: green; }
ul > li { color: pink; }
a[data-biscuit="dunderfunk"] { color: pink; }
div#antipattern:nth-child(3).horsehair [id="ding"] { color: yellow; }
{
selectors: [
'a[data-biscuit="dunderfunk"]',
'div#antipattern:nth-child(3).horsehair [id="ding"]',
'.fulvous',
'.Luddite',
'#orotund',
'ul > li'
],
simpleSelectors: {
all: [
'a',
'#antipattern',
'[data-biscuit="dunderfunk"]',
'div',
'.fulvous',
'.horsehair',
'[id="ding"]',
'li',
'.Luddite',
'#orotund',
'ul'
],
attributes: [
'[data-biscuit="dunderfunk"]',
'[id="ding"]'
],
classes: [
'.fulvous',
'.horsehair',
'.Luddite'
],
ids: [
'#antipattern',
'#orotund'
],
types: [
'a',
'div',
'li',
'ul'
]
}
}
Why?
Short answer: code review and analysis.
We all have our own reasons for wanting the review/analysis tools that we want. But if you need a prompt, here are some situations in which you might find list-selectors
useful:
- You want an overview of what's going on in some CSS. A nice organized list of all the selectors in play would no doubt help.
- In CSS code-reviews, you want to ensure that selectors adhere to some established conventions (e.g. SUIT or BEM format, no ids, prefixed classes, whatever else). With this list, you can easily scan through all the selectors and assess conformance.
- You want a quick look at how Person-or-Company X that you admire writes CSS selectors, names classes, etc. So feed their CSS (even minified) into one end of the tube, and get a selector list out the other end.
- You want to write a script that compares the selectors your team has actually used against a list of selectors that you are allowing yourself. This plugin will give you the "actual" (which you could compare with the "expected").
And so on.
Usage
Use it as a standalone Node function. Feed it globs of files or a URL, (optional) options, and a callback that will receive the selector list object.
- {string|string[]} source - Can be a single file glob, or an array of file globs that work together, or the URL of a remote CSS file. URLs are identified by an opening
http
, so don't forget that. The array of file globs is made possible by multimatch; if you'd like more details about usage and expected matches, have a look at the multimatch tests. - {object} [options] - Optional options: see Options.
- {function} callback - A callback function that will receive the generated list as an argument. If no selectors are found, it will receive an empty object.
Example
var listSelectors = require('list-selectors');
listSelectors(
['style/**/*.css', '!style/normalize.css'],
{ include: ['ids', 'classes'] },
function(myList) {
console.log(myList);
}
);
As a CLI
As with the standalone function, you feed it globs of files and options. You can pass an array of globs to make multimatch patterns (however, if you use !
or other special characters in your file globs, make sure that you wrap the glob in quotation marks or else your terminal will be flummoxed — see the last example below); and you can pass a URL to a remote CSS file.
The output is converted to a string with JSON.stringify()
and written to stdout
. You can read it in your terminal or pipe it to a file or another process.
Flags
-p
or --pretty
: This will add line breaks and tabs to make the JSON more legible, if your goal is to read it with human eyes.-i
or --include
: See Options.
Example
list-selectors foo.css
list-selectors foo.css -p -i classes
list-selectors https://www.npmjs.com/static/css/index.css
list-selectors "style/**/*.css" "!style/normalize.css"
As PostCSS Plugin
Consume it as a PostCSS plugin, in accordance with your chosen method of consuming PostCSS plugins.
Pass it (optional) options and a callback that will receive the output object. Then have your way with it.
Examples
With Gulp and gulp-postcss, you can just string it in there with your other plugins.
var gulp = require('gulp');
var gulpPostcss = require('gulp-postcss');
var listSelectors = require('listSelectors');
var customProperties = require('postcss-custom-properties');
gulp.task('analyzeCss', function() {
return gulp.src(['style/**/*.css', '!style/normalize.css'])
.pipe(postcss([
customProperties(),
listSelectors(doSomethingWithList)
]))
.pipe(gulp.dest('./dest'));
});
function doSomethingWithList(list) {
console.log(list);
}
Straight PostCSS:
var postcss = require('postcss');
var listSelectors = require('listSelectors');
var result;
var css = fs.readFileSync('foo.css', 'utf8');
var listOpts = { include: 'ids' };
postcss(listSimpleSelectors(listOpts, function(list) { result = list; }))
.process(css);
console.log(result);
Options
include
{string|string[]}
Only include a subset of lists in the output.
Possible values are:
'selectors'
: Only the complete list of full selectors.'simpleSelectors'
: Only the complete list of simple selectors.'simple'
: Same as 'simpleSelectors'
.'attributes'
: Only attributes.'classes'
: Only classes.'ids'
: Only ids.'types'
: Only types.
Caveats
- Anything within parentheses will be ignored. One situation in which you might use a selector in parentheses is with
:not
, e.g. .foo:not(.bar)
— and in that case, .bar
will not be included in the list (unless it's used elsewhere).