🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
Sign inDemoInstall
Socket

postcss-minify-selectors

Package Overview
Dependencies
Maintainers
1
Versions
68
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

postcss-minify-selectors - npm Package Compare versions

Comparing version

to
1.4.0

4

CHANGELOG.md

@@ -0,1 +1,5 @@

# 1.4.0
* Update to postcss-selector-parser to greatly improve parsing logic.
# 1.3.1

@@ -2,0 +6,0 @@

122

index.js
'use strict';
var uniqs = require('uniqs');
var minAttributes = require('./lib/transformAttributes');
var postcss = require('postcss');
var comma = postcss.list.comma;
var normalize = require('normalize-selector');
var balanced = require('node-balanced');
var natural = require('javascript-natural-sort');
var roq = require('./lib/replaceOutsideQuotes');
var unquote = require('./lib/unquote');
var parser = require('postcss-selector-parser');
function uniq (params, map) {

@@ -20,56 +20,92 @@ var transform = uniqs(comma(params).map(function (selector) {

function optimiseSelector (rule) {
function optimiseAtRule (rule) {
rule.params = normalize(uniq(rule.params));
}
function getParsed (selectors, callback) {
return parser(callback).process(selectors).result;
}
/**
* Can unquote attribute detection from mothereff.in
* Copyright Mathias Bynens <https://mathiasbynens.be/>
* https://github.com/mathiasbynens/mothereff.in
*/
var escapes = /\\([0-9A-Fa-f]{1,6})[ \t\n\f\r]?/g;
var range = /[\u0000-\u002c\u002e\u002f\u003A-\u0040\u005B-\u005E\u0060\u007B-\u009f]/;
function canUnquote (value) {
value = unquote(value);
if (value) {
value = value.replace(escapes, 'a').replace(/\\./g, 'a');
return !(range.test(value) || /^(?:-?\d|--)/.test(value));
}
return false;
}
function optimise (rule) {
var selector = rule._selector && rule._selector.raw || rule.selector;
// Ensure that the selector list contains no duplicates
selector = uniq(selector, true).map(function (sel) {
return roq(sel, function (range) {
// Remove the star from *qualified* star selectors
// TODO: Improve the parsing here - currently it just skips the selector
// if there is a comment.
range = range.replace(/(?=\S*?)(\s+)(?=\S)/, ' ');
if (!~range.indexOf('/*') && !~range.indexOf('*/')) {
return range.replace(/(\*)([^\+~=>\s])/g, '$2');
rule.selector = getParsed(selector, function (selectors) {
selectors.nodes.sort(function (a, b) {
return natural(String(a), String(b));
});
selectors.eachAttribute(function (selector) {
if (selector.value) {
// Join selectors that are split over new lines
selector.value = selector.value.replace(/\\\n/g, '').trim();
if (canUnquote(selector.value)) {
selector.value = unquote(selector.value);
}
selector.operator = selector.operator.trim();
}
return range;
if (selector.raw) {
selector.raw.insensitive = '';
}
selector.attribute = selector.attribute.trim();
});
}).map(minAttributes).join(',');
// Minimise from and 100% in keyframe rules
if (rule.parent.type !== 'root' && ~rule.parent.name.indexOf('keyframes')) {
selector = comma(selector).map(function (value) {
if (value === 'from') {
return '0%';
var uniques = [];
selectors.eachInside(function (selector) {
// Trim whitespace around the value
selector.spaces.before = selector.spaces.after = '';
// Minimise from/100%
if (selector.value === 'from') { selector.value = '0%'; }
if (selector.value === '100%') { selector.value = 'to'; }
if (selector.type === 'combinator') {
var value = selector.value.trim();
selector.value = value.length ? value : ' ';
}
if (value === '100%') {
return 'to';
if (selector.type === 'selector' && selector.type !== 'pseudo') {
if (!~uniques.indexOf(String(selector))) {
uniques.push(String(selector));
} else {
selector.removeSelf();
}
}
return value;
}).join(',');
}
// Trim whitespace around selector combinators
rule.selector = roq(selector, function (range) {
// Trim any useless space inside negation pseudo classes
if (range) {
range = balanced.replacements({
source: range,
open: ':not(',
close: ')',
replace: function (body, head, tail) {
return head + uniq(body) + tail;
});
uniques = [];
selectors.eachPseudo(function (pseudo) {
pseudo.eachInside(function (selector) {
if (selector.type === 'selector' && selector.type !== 'pseudo') {
if (!~uniques.indexOf(String(selector))) {
uniques.push(String(selector));
} else {
selector.removeSelf();
}
}
});
return range.replace(/\s*([>+~])\s*/g, '$1');
}
return range;
});
selectors.eachUniversal(function (selector) {
var next = selector.next();
if (next && next.type !== 'combinator') {
selector.removeSelf();
}
});
});
}
function optimiseAtRule (rule) {
rule.params = normalize(uniq(rule.params));
}
module.exports = postcss.plugin('postcss-minify-selectors', function () {
return function (css) {
css.eachRule(optimiseSelector);
css.eachRule(optimise);
css.eachAtRule(optimiseAtRule);
};
});
{
"name": "postcss-minify-selectors",
"version": "1.3.1",
"version": "1.4.0",
"description": "Minify selectors with PostCSS.",

@@ -35,7 +35,7 @@ "main": "index.js",

"javascript-natural-sort": "^0.7.1",
"node-balanced": "0.0.14",
"normalize-selector": "0.0.3-a",
"postcss": "^4.1.2",
"postcss": "^4.1.11",
"postcss-selector-parser": "0.0.5",
"uniqs": "^2.0.0"
}
}