Socket
Socket
Sign inDemoInstall

list-selectors

Package Overview
Dependencies
77
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.1.2 to 0.2.0

lib/plugin.js

3

CHANGELOG.md
# Changelog
## v0.2.0
- Major refactor, including upgrade to PostCSS 4.1.
## v0.1.2

@@ -4,0 +7,0 @@ - Updated dependencies.

225

index.js
'use strict';
var _ = require('lodash');
var fs = require('fs');
var globby = require('globby');
var request = require('request');
var postcss = require('postcss');
var chalk = require('chalk');
var selectorProcessors = require('./lib/selectorProcessors');
var standalone = require('./lib/standalone');
standalone.plugin = require('./lib/plugin');
var logPrefix = chalk.bold('list-selectors: ');
// These are the valid `include` option values.
var TOP_LEVEL_INCLUDES = [
'selectors',
'simpleSelectors',
'simple'
];
var SIMPLE_INCLUDES = [
'classes',
'ids',
'attributes',
'types'
];
/**
* The function that people will run.
*
* Arguments are polymorphic, and the process will change based on the type of input.
*
* @param {string|string[]} [source] - If the first argument is a string or array (of strings),
* you are passing a glob (or globs) or a URL -- in which case, you are not using it as a
* postcss plugin, but as a standalone function via node or the CLI. If this argument is
* absent, we have to assume you're using the function a as a postcss plugin.
* @param {object} [options]
* @param {function} [cb] - A callback that will receive the result list of selectors
* as an argument.
* @return {undefined|function} If used as a postcss plugin, listSelectors will return a
* function that fits into your postcss piping. Otherwise, it doesn't return anything:
* its results are available for use in the callback.
*/
function listSelectors(/* [source, options, cb] */) {
var firstArg = arguments[0];
var source = (!_.isPlainObject(firstArg) && !_.isFunction(firstArg)) ? firstArg : false;
var polyIndex = (source) ? 1 : 0;
var mysteryArg = arguments[polyIndex]; // Could be options or callback
var opts = (_.isPlainObject(mysteryArg)) ? mysteryArg : {};
var cb = (_.isFunction(mysteryArg)) ? mysteryArg : arguments[polyIndex + 1] || _.noop;
// Standalone function is indicated by the initial file glob
if (source) {
listSelectorsStandalone(source, opts, cb);
} else {
return _.partial(listSelectorsPostcss, opts, cb);
}
}
/**
* The postcss plugin at the heart of everything.
*
* @param {object} opts
* @param {function} cb
* @param {object} cssTree - CSS Node Tree from PostCSS processing
* @return {object} The same cssTree we got in, for other PostCSS plugins
* that follow to use
*/
function listSelectorsPostcss(opts, cb, cssTree) {
var result = {};
// Run through all the rules and accumulate a list of selectors
// parsed out by PostCSS
var accumulatedSelectors = [];
cssTree.eachRule(function(rule) {
// Ignore keyframes, which can log e.g. 10%, 20% as selectors
if (rule.parent.type === 'atrule' && /keyframes/.test(rule.parent.name)) { return; }
rule.selectors.forEach(function(selector) {
accumulatedSelectors.push(selector);
});
});
// If no selectors were found, results are an empty object
if (_.isEmpty(accumulatedSelectors)) {
console.log(logPrefix + chalk.red(
'Failed to find any selectors at all in the source files you provided. ' +
'You are going to get an empty selector list.'
));
cb({});
return cssTree;
}
// Add sorted, unique selectors to results
result.selectors = _.sortBy(_.uniq(accumulatedSelectors), selectorSortFn);
// Add sorted, unique simple selectors to results
result.simpleSelectors = {};
result.simpleSelectors.all = _.sortBy(
_.uniq(selectorProcessors.reduceToSimpleSelectors(result.selectors)),
selectorSortFn
);
// Add all of the category lists (of simple selectors) to results
result.simpleSelectors.ids = selectorProcessors.getIds(result.simpleSelectors.all);
result.simpleSelectors.classes = selectorProcessors.getClasses(result.simpleSelectors.all);
result.simpleSelectors.attributes = selectorProcessors.getAttributes(result.simpleSelectors.all);
result.simpleSelectors.types = selectorProcessors.getTypes(result.simpleSelectors.all);
// Refine the results according to any `include` options passed
result = processIncludes(result, opts.include);
// Call the callback as promised, passing the result as an argument
cb(result);
return cssTree;
}
/**
* When using this as a standalone function or via CLI, we'll need
* to get the source files before processing. They might be local,
* identified with globs, or remote, identified with a URL.
* Get the source files, accumulate them into a string, then
* run that string through postcss with listSelectors as a plugin.
*
* Parameters are the same as for listSelectors, above
* (and listSelectors will pass them).
*/
function listSelectorsStandalone(source, opts, cb) {
var fullCss = '';
if (_.startsWith(source, 'http')) {
processRemoteCss();
} else {
processLocalCss();
}
function processRemoteCss() {
var url = (_.isArray(source)) ? source[0] : source;
request(url, function(err, resp, body) {
if (err) { throw chalk.red(err); }
if (resp.statusCode !== 200) {
console.log(
logPrefix + chalk.red('Failed to fetch ') + chalk.yellow.underline(url) +
chalk.red('. Maybe you flubbed the url?')
);
body = '';
}
postcss(listSelectors(opts, cb)).process(body);
});
}
function processLocalCss() {
globby(source, function(err, filePaths) {
if (err) { throw chalk.red(err); }
if (!filePaths.length) {
console.log(
logPrefix + chalk.red('Failed to find any files matching your glob ') +
chalk.yellow.underline(source)
);
}
filePaths.forEach(function(filePath) {
fullCss += fs.readFileSync(filePath, { encoding: 'utf8' });
});
postcss(listSelectors(opts, cb)).process(fullCss);
});
}
}
/**
* Used to sort selectors alphabetically, ignoring initial category
* distinguishing punctuation like `#`, `.`, and `[`.
*
* @param {string} selector
* @return {string} The sortable selector:
* lowercased, stripped of initial punctuation
*/
function selectorSortFn(selector) {
var lowerNoPseudo = selector.split(':')[0].toLowerCase();
return (/^[#\.\[]/.test(selector)) ? lowerNoPseudo.substr(1) : lowerNoPseudo;
}
/**
* Filter a full selector list according to specific `include` options.
*
* @param {object} selectorList
* @param {string|object} includes
* @return {object} The filtered selectorList
*/
function processIncludes(selectorList, includes) {
if (!includes) { return selectorList; }
if (_.isString(includes)) { includes = [includes]; }
var result = _.reduce(includes, function(r, include) {
if (_.contains(TOP_LEVEL_INCLUDES, include)) {
if (_.contains(['simple', 'simpleSelectors'], include)) {
r.simpleSelectors = selectorList.simpleSelectors.all;
} else {
r[include] = selectorList[include];
}
return r;
}
if (_.contains(SIMPLE_INCLUDES, include)) {
r[include] = selectorList.simpleSelectors[include];
return r;
}
console.log(logPrefix + chalk.red('Invalid include "' + include + '" passed. ' +
'The possibilities are: ' +
TOP_LEVEL_INCLUDES.concat(SIMPLE_INCLUDES).join(', ') + '. ' +
'You\'ll get the full selector list now.'
));
return selectorList;
}, {});
return result;
}
module.exports = listSelectors;
module.exports = standalone;

@@ -12,3 +12,3 @@ {

"license": "MIT",
"version": "0.1.2",
"version": "0.2.0",
"description": "List the selectors used in your CSS. Use as a standalone function, CLI, or PostCSS plugin.",

@@ -40,13 +40,14 @@ "homepage": "https://github.com/davidtheclark/list-selectors",

"devDependencies": {
"eslint": "0.15.1",
"tape": "3.5.0"
"eslint": "0.18.0",
"tape": "4.0.0"
},
"dependencies": {
"chalk": "^1.0",
"globby": "^1.0",
"globby": "^2.0",
"lodash": "^3.0",
"minimist": "^1.0",
"postcss": "^4.0",
"postcss": "^4.1.0",
"postcss-log-warnings": "^0.1.2",
"request": "^2.0"
}
}

@@ -13,2 +13,4 @@ # list-selectors [![Build Status](https://travis-ci.org/davidtheclark/list-selectors.svg?branch=master)](https://travis-ci.org/davidtheclark/list-selectors)

*The latest version should be used as a PostCSS plugin only with PostCSS v4.1+.*
## Installation

@@ -43,3 +45,3 @@

// It also ignores capitalization. So you'd get
// `['#goo', '.faz', '.Freedom', '[href="..."]']` in that order.
// `['#goo', '.faz', '.Freedom', '[href="..."]']` in that order.
{

@@ -176,2 +178,8 @@ selectors: [

Just use the `plugin` method:
```js
var listSelectorPlugin = require('list-selectors').plugin;
```
Pass it (optional) options and a callback that will receive the output object. Then have your way with it.

@@ -186,3 +194,3 @@

var gulpPostcss = require('gulp-postcss');
var listSelectors = require('listSelectors');
var listSelectorsPlugin = require('listSelectors').plugin;
var customProperties = require('postcss-custom-properties');

@@ -194,3 +202,3 @@

customProperties(),
listSelectors(doSomethingWithList)
listSelectorsPlugin(doSomethingWithList)
]))

@@ -200,4 +208,4 @@ .pipe(gulp.dest('./dest'));

function doSomethingWithList(list) {
console.log(list);
function doSomethingWithList(mySelectorList) {
console.log(mySelectorList);
// ... do other things

@@ -211,11 +219,13 @@ }

var postcss = require('postcss');
var listSelectors = require('listSelectors');
var listSelectorsPlugin = require('listSelectors').plugin;
var result;
var mySelectorList;
var css = fs.readFileSync('foo.css', 'utf8');
var listOpts = { include: 'ids' };
postcss(listSimpleSelectors(listOpts, function(list) { result = list; }))
.process(css);
console.log(result);
// ... do other things with result
postcss(listSelectorsPlugin(listOpts, function(list) { mySelectorList = list; }))
.process(css)
.then(function() {
console.log(mySelectorList);
// ... do other things with result
});
```

@@ -222,0 +232,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc