Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More โ†’
Socket
Sign inDemoInstall
Socket

dropcss

Package Overview
Dependencies
Maintainers
1
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dropcss - npm Package Compare versions

Comparing version 0.5.0 to 1.0.0

176

dist/dropcss.cjs.js

@@ -7,3 +7,3 @@ /**

* An exceptionally fast, thorough and tiny unused-CSS cleaner
* https://github.com/leeoniya/dropcss (v0.5.0)
* https://github.com/leeoniya/dropcss (v1.0.0)
*/

@@ -15,15 +15,17 @@

var ATTRS = 2;
var TEXT = 3;
var TAG_CLOSE = 4;
var TAG_CLOSE = 3;
function tokenize(html, keepText) {
var RE = {
// TODO: handle self-closed tags <div/> ?
TAG_HEAD: /\s*<([a-z0-9_-]+)(?:\s+([^>]*))?>\s*/my,
TAG_TEXT: /\s*[^<]*/my,
TAG_CLOSE: /\s*<\/[a-z0-9_-]+>\s*/my,
};
var VOIDS = new Set("area base br col command embed hr img input keygen link meta param source track wbr".split(" "));
var RE_ATTRS = /([\w-]+)(?:="([^"]*)"|='([^']*)'|=(\S+))?/gm;
// doctype, comments, meta, style, link & script tags. TODO: CDATA
var NASTIES = /<!doctype[^>]*>|<!--[\s\S]*?-->|<script[^>]*>[\s\S]*?<\/script>|<style[^>]*>[\s\S]*?<\/style>|<link[^>]*>|<meta[^>]*>/gmi;
var RE_ATTRS = /([\w-]+)(?:="([^"]*)"|='([^']*)'|=(\S+))?/gm;
var RE = {
// TODO: handle self-closed tags <div/> ?
TAG_HEAD: /\s*<([a-z0-9_-]+)(?:\s+([^>]*))?>\s*/my,
TEXT: /\s*[^<]*/my,
TAG_CLOSE: /\s*<\/[a-z0-9_-]+>\s*/my,
};
function tokenize(html) {
var pos = 0, m, tokens = [];

@@ -37,21 +39,2 @@

var voidTags = {
area: true,
base: true,
br: true,
col: true,
command: true,
embed: true,
hr: true,
img: true,
input: true,
keygen: true,
link: true,
meta: true,
param: true,
source: true,
track: true,
wbr: true
};
function next() {

@@ -83,3 +66,3 @@ m = RE.TAG_CLOSE.exec(html);

if (tag in voidTags)
if (VOIDS.has(tag))
{ tokens.push(TAG_CLOSE); }

@@ -90,10 +73,6 @@

m = RE.TAG_TEXT.exec(html);
m = RE.TEXT.exec(html);
if (m != null) {
syncPos(RE.TAG_TEXT);
if (keepText)
{ tokens.push(TEXT, m[0]); }
}
if (m != null)
{ syncPos(RE.TEXT); }
}

@@ -104,2 +83,4 @@

syncPos({lastIndex: 0});
return tokens;

@@ -112,13 +93,33 @@ }

function node(parent, tagName, attrs) {
var isText = tagName == '#';
return {
tagName: tagName,
attributes: attrs,
classList: !isText && attrs != null && attrs.has('class') ? new Set(attrs.get('class').split(/\s+/g)) : EMPTY_SET,
classList: attrs != null && attrs.has('class') ? new Set(attrs.get('class').split(/\s+/g)) : EMPTY_SET,
parentNode: parent,
childNodes: isText ? null : [],
childNodes: [],
};
}
// adds ._ofTypes: {<tagName>: [...]} to parent
// adds ._typeIdx to childNodes
function getSibsOfType(par, tagName) {
if (par != null) {
var ofTypes = (par._ofTypes = par._ofTypes || {});
if (!(tagName in ofTypes)) {
var typeIdx = 0;
ofTypes[tagName] = par.childNodes.filter(function (n) {
if (n.tagName == tagName) {
n._typeIdx = typeIdx++;
return true;
}
});
}
return ofTypes[tagName];
}
return null;
}
function build(tokens, each) {

@@ -149,7 +150,2 @@ var targ = node(null, "root", EMPTY_SET), idx;

break;
case TEXT:
var n = node(targ, '#', EMPTY_SET);
targ.childNodes.push(n);
each(n, targ.childNodes.length - 1);
break;
}

@@ -185,7 +181,6 @@ }

var _export_parse_ = function (html, pruneText) {
// remove doctype, comments, meta, style, link & script tags. TODO: CDATA
html = html.replace(/<!doctype[^>]*>|<!--[\s\S]*?-->|<script[^>]*>[\s\S]*?<\/script>|<style[^>]*>[\s\S]*?<\/style>|<link[^>]*>|<meta[^>]*>/gmi, '');
var _export_parse_ = function (html) {
html = html.replace(NASTIES, '');
var tokens = tokenize(html, !pruneText);
var tokens = tokenize(html);

@@ -595,2 +590,4 @@ var ctx = {

function _nthChild(pos, val) {
var res;
if (val == 'odd')

@@ -646,5 +643,7 @@ { res = pos % 2 == 1; }

var n = ctx.node;
var tag = n.tagName;
tidx = n.idx;
par = n.parentNode;
var len = par ? par.childNodes.length : 1;
var tsibs = (void 0);

@@ -655,5 +654,2 @@ switch (name) {

break;
case 'empty':
res = n.tagName != '#' && n.childNodes.length == 0;
break;
case 'first-child':

@@ -674,2 +670,22 @@ res = tidx == 0;

break;
case 'first-of-type':
tsibs = getSibsOfType(par, tag);
res = n._typeIdx == 0;
break;
case 'last-of-type':
tsibs = getSibsOfType(par, tag);
res = n._typeIdx == tsibs.length - 1;
break;
case 'only-of-type':
tsibs = getSibsOfType(par, tag);
res = tsibs.length == 1;
break;
case 'nth-of-type':
tsibs = getSibsOfType(par, tag);
res = _nthChild(n._typeIdx + 1, val);
break;
case 'nth-last-of-type':
tsibs = getSibsOfType(par, tag);
res = _nthChild(tsibs.length - n._typeIdx, val);
break;
}

@@ -737,3 +753,3 @@

var pseudoAssertable = /:(?:first|last|nth|only|not|empty)\b/; // |lang
var pseudoAssertable = /:(?:first|last|nth|only|not)\b/; // |lang

@@ -752,4 +768,15 @@ function stripNonAssertablePseudos(sel) {

function removeBackwards(css, defs, used) {
for (var i = defs.length - 1; i > -1; i--) {
var d = defs[i];
if (!used.has(d[2]))
{ css = splice(css, d[0], d[1], ''); }
}
return css;
}
function dropKeyFrames(css) {
var matches = [];
var defs = [];
var used = new Set();

@@ -762,3 +789,3 @@

var ch = takeUntilMatchedClosing(css, RE.lastIndex);
matches.push([m.index, m[0].length + ch.length + 1, m[1]]);
defs.push([m.index, m[0].length + ch.length + 1, m[1]]);
}

@@ -775,12 +802,31 @@

// purge backwards
var css2 = css;
for (var i = matches.length - 1; i > -1; i--) {
var ma = matches[i];
return removeBackwards(css, defs, used);
}
if (!used.has(ma[2]))
{ css2 = splice(css2, ma[0], ma[1], ''); }
function dropFontFaces(css) {
var defs = [];
var used = new Set();
// defined
var RE = /@font-face[\s\S]+?font-family:\s*(['"\w-]+)[^}]+\}/gm, m;
while (m = RE.exec(css)) {
var clean = m[1].replace(/['"]/gm, '');
defs.push([m.index, m[0].length, clean]);
}
return css2;
// used
var RE2 = /font-family:([^;!}]+)/gm;
while (m = RE2.exec(css)) {
var inDef = defs.some(function (d) { return m.index > d[0] && m.index < d[0] + d[1]; });
if (!inDef) {
m[1].trim().split(",").forEach(function (a) {
used.add(a.trim().replace(/['"]/gm, ''));
});
}
}
return removeBackwards(css, defs, used);
}

@@ -897,2 +943,4 @@

out = dropFontFaces(out);
// log.forEach(e => console.log(e[0], e[1]));

@@ -899,0 +947,0 @@

@@ -7,3 +7,3 @@ /**

* An exceptionally fast, thorough and tiny unused-CSS cleaner
* https://github.com/leeoniya/dropcss (v0.5.0)
* https://github.com/leeoniya/dropcss (v1.0.0)
*/

@@ -19,15 +19,17 @@

var ATTRS = 2;
var TEXT = 3;
var TAG_CLOSE = 4;
var TAG_CLOSE = 3;
function tokenize(html, keepText) {
var RE = {
// TODO: handle self-closed tags <div/> ?
TAG_HEAD: /\s*<([a-z0-9_-]+)(?:\s+([^>]*))?>\s*/my,
TAG_TEXT: /\s*[^<]*/my,
TAG_CLOSE: /\s*<\/[a-z0-9_-]+>\s*/my,
};
var VOIDS = new Set("area base br col command embed hr img input keygen link meta param source track wbr".split(" "));
var RE_ATTRS = /([\w-]+)(?:="([^"]*)"|='([^']*)'|=(\S+))?/gm;
// doctype, comments, meta, style, link & script tags. TODO: CDATA
var NASTIES = /<!doctype[^>]*>|<!--[\s\S]*?-->|<script[^>]*>[\s\S]*?<\/script>|<style[^>]*>[\s\S]*?<\/style>|<link[^>]*>|<meta[^>]*>/gmi;
var RE_ATTRS = /([\w-]+)(?:="([^"]*)"|='([^']*)'|=(\S+))?/gm;
var RE = {
// TODO: handle self-closed tags <div/> ?
TAG_HEAD: /\s*<([a-z0-9_-]+)(?:\s+([^>]*))?>\s*/my,
TEXT: /\s*[^<]*/my,
TAG_CLOSE: /\s*<\/[a-z0-9_-]+>\s*/my,
};
function tokenize(html) {
var pos = 0, m, tokens = [];

@@ -41,21 +43,2 @@

var voidTags = {
area: true,
base: true,
br: true,
col: true,
command: true,
embed: true,
hr: true,
img: true,
input: true,
keygen: true,
link: true,
meta: true,
param: true,
source: true,
track: true,
wbr: true
};
function next() {

@@ -87,3 +70,3 @@ m = RE.TAG_CLOSE.exec(html);

if (tag in voidTags)
if (VOIDS.has(tag))
{ tokens.push(TAG_CLOSE); }

@@ -94,10 +77,6 @@

m = RE.TAG_TEXT.exec(html);
m = RE.TEXT.exec(html);
if (m != null) {
syncPos(RE.TAG_TEXT);
if (keepText)
{ tokens.push(TEXT, m[0]); }
}
if (m != null)
{ syncPos(RE.TEXT); }
}

@@ -108,2 +87,4 @@

syncPos({lastIndex: 0});
return tokens;

@@ -116,13 +97,33 @@ }

function node(parent, tagName, attrs) {
var isText = tagName == '#';
return {
tagName: tagName,
attributes: attrs,
classList: !isText && attrs != null && attrs.has('class') ? new Set(attrs.get('class').split(/\s+/g)) : EMPTY_SET,
classList: attrs != null && attrs.has('class') ? new Set(attrs.get('class').split(/\s+/g)) : EMPTY_SET,
parentNode: parent,
childNodes: isText ? null : [],
childNodes: [],
};
}
// adds ._ofTypes: {<tagName>: [...]} to parent
// adds ._typeIdx to childNodes
function getSibsOfType(par, tagName) {
if (par != null) {
var ofTypes = (par._ofTypes = par._ofTypes || {});
if (!(tagName in ofTypes)) {
var typeIdx = 0;
ofTypes[tagName] = par.childNodes.filter(function (n) {
if (n.tagName == tagName) {
n._typeIdx = typeIdx++;
return true;
}
});
}
return ofTypes[tagName];
}
return null;
}
function build(tokens, each) {

@@ -153,7 +154,2 @@ var targ = node(null, "root", EMPTY_SET), idx;

break;
case TEXT:
var n = node(targ, '#', EMPTY_SET);
targ.childNodes.push(n);
each(n, targ.childNodes.length - 1);
break;
}

@@ -189,7 +185,6 @@ }

var _export_parse_ = function (html, pruneText) {
// remove doctype, comments, meta, style, link & script tags. TODO: CDATA
html = html.replace(/<!doctype[^>]*>|<!--[\s\S]*?-->|<script[^>]*>[\s\S]*?<\/script>|<style[^>]*>[\s\S]*?<\/style>|<link[^>]*>|<meta[^>]*>/gmi, '');
var _export_parse_ = function (html) {
html = html.replace(NASTIES, '');
var tokens = tokenize(html, !pruneText);
var tokens = tokenize(html);

@@ -599,2 +594,4 @@ var ctx = {

function _nthChild(pos, val) {
var res;
if (val == 'odd')

@@ -650,5 +647,7 @@ { res = pos % 2 == 1; }

var n = ctx.node;
var tag = n.tagName;
tidx = n.idx;
par = n.parentNode;
var len = par ? par.childNodes.length : 1;
var tsibs = (void 0);

@@ -659,5 +658,2 @@ switch (name) {

break;
case 'empty':
res = n.tagName != '#' && n.childNodes.length == 0;
break;
case 'first-child':

@@ -678,2 +674,22 @@ res = tidx == 0;

break;
case 'first-of-type':
tsibs = getSibsOfType(par, tag);
res = n._typeIdx == 0;
break;
case 'last-of-type':
tsibs = getSibsOfType(par, tag);
res = n._typeIdx == tsibs.length - 1;
break;
case 'only-of-type':
tsibs = getSibsOfType(par, tag);
res = tsibs.length == 1;
break;
case 'nth-of-type':
tsibs = getSibsOfType(par, tag);
res = _nthChild(n._typeIdx + 1, val);
break;
case 'nth-last-of-type':
tsibs = getSibsOfType(par, tag);
res = _nthChild(tsibs.length - n._typeIdx, val);
break;
}

@@ -741,3 +757,3 @@

var pseudoAssertable = /:(?:first|last|nth|only|not|empty)\b/; // |lang
var pseudoAssertable = /:(?:first|last|nth|only|not)\b/; // |lang

@@ -756,4 +772,15 @@ function stripNonAssertablePseudos(sel) {

function removeBackwards(css, defs, used) {
for (var i = defs.length - 1; i > -1; i--) {
var d = defs[i];
if (!used.has(d[2]))
{ css = splice(css, d[0], d[1], ''); }
}
return css;
}
function dropKeyFrames(css) {
var matches = [];
var defs = [];
var used = new Set();

@@ -766,3 +793,3 @@

var ch = takeUntilMatchedClosing(css, RE.lastIndex);
matches.push([m.index, m[0].length + ch.length + 1, m[1]]);
defs.push([m.index, m[0].length + ch.length + 1, m[1]]);
}

@@ -779,12 +806,31 @@

// purge backwards
var css2 = css;
for (var i = matches.length - 1; i > -1; i--) {
var ma = matches[i];
return removeBackwards(css, defs, used);
}
if (!used.has(ma[2]))
{ css2 = splice(css2, ma[0], ma[1], ''); }
function dropFontFaces(css) {
var defs = [];
var used = new Set();
// defined
var RE = /@font-face[\s\S]+?font-family:\s*(['"\w-]+)[^}]+\}/gm, m;
while (m = RE.exec(css)) {
var clean = m[1].replace(/['"]/gm, '');
defs.push([m.index, m[0].length, clean]);
}
return css2;
// used
var RE2 = /font-family:([^;!}]+)/gm;
while (m = RE2.exec(css)) {
var inDef = defs.some(function (d) { return m.index > d[0] && m.index < d[0] + d[1]; });
if (!inDef) {
m[1].trim().split(",").forEach(function (a) {
used.add(a.trim().replace(/['"]/gm, ''));
});
}
}
return removeBackwards(css, defs, used);
}

@@ -901,2 +947,4 @@

out = dropFontFaces(out);
// log.forEach(e => console.log(e[0], e[1]));

@@ -903,0 +951,0 @@

@@ -1,2 +0,2 @@

/*! https://github.com/leeoniya/dropcss (v0.5.0) */
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):(e=e||self).dropcss=r()}(this,function(){"use strict";var e=1,r=2,n=3,t=4;var a=new Set;function s(e,r,n){var t="#"==r;return{tagName:r,attributes:n,classList:!t&&null!=n&&n.has("class")?new Set(n.get("class").split(/\s+/g)):a,parentNode:e,childNodes:t?null:[]}}var i=function(i,c){var l=function(a,s){var i,c={TAG_HEAD:/\s*<([a-z0-9_-]+)(?:\s+([^>]*))?>\s*/my,TAG_TEXT:/\s*[^<]*/my,TAG_CLOSE:/\s*<\/[a-z0-9_-]+>\s*/my},l=/([\w-]+)(?:="([^"]*)"|='([^']*)'|=(\S+))?/gm,u=0,o=[];function d(e){for(var r in u=e.lastIndex,c)c[r].lastIndex=u}var f={area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0};function h(){if(null!=(i=c.TAG_CLOSE.exec(a)))return d(c.TAG_CLOSE),void o.push(t);if(null==(i=c.TAG_HEAD.exec(a)))null!=(i=c.TAG_TEXT.exec(a))&&(d(c.TAG_TEXT),s&&o.push(n,i[0]));else{d(c.TAG_HEAD);var u=i[1];o.push(e,u);var h=i[2];if(null!=h){for(var p,v=new Map;p=l.exec(h);)v.set(p[1],(p[2]||p[3]||p[4]||"").trim());o.push(r,v)}u in f&&o.push(t)}}for(;u<a.length;)h();return o}(i=i.replace(/<!doctype[^>]*>|<!--[\s\S]*?-->|<script[^>]*>[\s\S]*?<\/script>|<style[^>]*>[\s\S]*?<\/style>|<link[^>]*>|<meta[^>]*>/gim,""),!c),u={nodes:[],tag:new Set(["*"]),class:new Set,attr:new Set};!function(i,c){for(var l,u=s(null,"root",a),o=0;o<i.length;o++)switch(i[o]){case e:var d=i[++o],f=a;i[o+1]===r&&(f=i[o+=2]),l=u.childNodes.length,u.childNodes.push(u=s(u,d,f)),c(u,l);break;case t:u=u.parentNode;break;case n:var h=s(u,"#",a);u.childNodes.push(h),c(h,u.childNodes.length-1)}}(l,function(e,r){return function(e,r,n){e.idx=r;var t=e.attributes;n.tag.add(e.tagName),e.classList.forEach(function(e){return n.class.add(e)}),t.has("id")&&n.attr.add("[id="+t.get("id")+"]"),t.has("type")&&n.attr.add("[type="+t.get("type")+"]"),n.nodes.push(e)}(e,r,u)});return u},c=/\s*\/\*[\s\S]*?\*\/\s*/gm,l=/\s*[>~+]\s*|\s+/g,u=1,o=2,d=3,f=4,h=5;function p(e,r){for(var n="",t=1;"{"==e[r]?t++:"}"==e[r]&&t--,0!=t;)n+=e[r++];return n}function v(e){var r,n={RULE_HEAD:/\s*([^{;]+?)\s*[{;]\s*/my,RULE_TAIL:/\s*([^}]*?)\s*\}/my,AT_TAIL:/\s*\}/my,RULE_FULL:/\s*([^{]*?)\{([^}]+?)\}/my},t=0,a=0,s=[];function i(e){for(var r in a=e.lastIndex,n)n[r].lastIndex=a}function c(){if(t>0&&null!=(r=n.AT_TAIL.exec(e)))return t--,s.push(o),void i(n.AT_TAIL);if(null!=(r=n.RULE_HEAD.exec(e))){var c=r[1];if(i(n.RULE_HEAD),"@"==c[0])switch(c.match(/@[a-z-]+/)[0]){case"@media":case"@supports":case"@document":t++,s.push(u,c);break;case"@import":case"@charset":case"@namespace":s.push(h,c+";");break;default:t++;var v=p(e,a);i({lastIndex:a+v.length}),s.push(u,c,h,v)}else s.push(d,(m=r[1],(x=m.split(/\s*,\s*/gm)).push(x.map(function(e){return function(e){return e.replace(/:?:[a-z-]+(?:\([^()]+\))?/gm,"")}(e).trim().replace(/(\.|#|\[)/gm," $1").replace(/\]/gm,"] ").trim().split(l)})),x)),r=n.RULE_TAIL.exec(e),s.push(f,r[1]),i(n.RULE_TAIL)}else a=e.length;var m,x}for(;a<e.length;)c();return s}function m(e,r){return r==e.tagName||"*"==r}function x(e,r,n,t){t=t||"=";var a=e.attributes;if(a.has(r)){var s=a.get(r);switch(t){case"=":return null==n||n==s;case"*=":return-1!=s.indexOf(n);case"^=":return s.startsWith(n);case"$=":return s.endsWith(n)}}return!1}function g(e,r){return e.classList.has(r)}function b(e,r){return e.some(function(e){return function e(r,n){var t,a,s,i,c,l;for(;n.idx>-1;){switch(r[n.idx]){case"_":t=r[--n.idx],l=m(n.node,t),n.idx--;break;case"#":a=r[--n.idx],l=x(n.node,"id",a,"="),n.idx--;break;case".":t=r[--n.idx],l=g(n.node,t),n.idx--;break;case"[":t=r[--n.idx],s=r[--n.idx],a=r[--n.idx],l=x(n.node,t,a,s),n.idx--;break;case":":t=r[--n.idx],a=r[--n.idx];var u=n.node;c=u.idx;var o=(i=u.parentNode)?i.childNodes.length:1;switch(t){case"not":l=!e(a,{node:n.node,idx:a.length-1});break;case"empty":l="#"!=u.tagName&&0==u.childNodes.length;break;case"first-child":l=0==c;break;case"last-child":l=c==o-1;break;case"only-child":l=1==o;break;case"nth-child":l=k(c+1,a);break;case"nth-last-child":l=k(o-c,a)}n.idx--;break;case" ":for(c=--n.idx,l=!1;!l&&null!=(i=n.node.parentNode);)n.idx=c,n.node=i,l=e(r,n);break;case">":n.idx--,null!=(i=n.node.parentNode)?(n.node=i,l=e(r,n)):l=!1;break;case"+":n.idx--,null!=(i=n.node.parentNode)&&n.node.idx>0?(n.node=i.childNodes[n.node.idx-1],l=e(r,n)):l=!1;break;case"~":if(n.idx--,l=!1,c=n.node.idx,null!=(i=n.node.parentNode)&&c>0)for(var d=0;d<c&&!l;d++)n.node=i.childNodes[d],l=e(r,n)}if(!l)break}return l}(r,{idx:r.length-1,node:e})})}var T=/^([+-]?\d*)?n([+-]\d+)?$/;function k(e,r){if("odd"==r)res=e%2==1;else if("even"==r)res=e%2==0;else if(/^\d+$/.test(r))res=e==+r;else{var n=function(e){var r=T.exec(e);if(null!=r){var n=r[1],t=r[2];return[n=null==n||"+"==n?1:"-"==n?-1:+n,t=null==t?0:+t]}return[0,0]}(r);res=function(e,r,n){if(r<0&&e<=0)return!1;if(-1===e)return n<=r;if(0===e)return n===r;if(1===e)return r<0||n>=r;var t=r%e;return t<0&&(t+=e),e>1?n>=r&&n%e===t:(e*=-1,n<=r&&n%e===t)}(n[0],n[1],e)}return res}var E=function(e,r){return b(e,Array.isArray(r)?r:function e(r){var n,t={IDENT:/([\w*-]+)/iy,ATTR:/([\w-]+)(?:(.?=)"?([^\]]*?)"?)?\]/iy,PSEUDO:/([\w-]+)(?:\(([^)]*)\))?/iy,MODE:/\s*[:.#\[]\s*/iy,COMB:/\s*[>~+]\s*|\s+/iy},a=0,s=[],i=-1;function c(e){for(var r in a=e.lastIndex,t)t[r].lastIndex=a}function l(){var l=!1;if(n=t.COMB.exec(r)){l=!0;var u=n[0].trim();""==u&&(u=" "),s.push(u),c(t.COMB),i=a}else if(n=t.MODE.exec(r)){l=!0;var o=n[0].trim();c(t.MODE),":"==o?(n=t.PSEUDO.exec(r),s.splice(i+1,0,null!=n[2]&&"not"==n[1]?e(n[2]):n[2],n[1],o),c(t.PSEUDO)):"["==o?(n=t.ATTR.exec(r),s.splice(i+1,0,n[3],n[2],n[1],o),c(t.ATTR)):(n=t.IDENT.exec(r),s.push(n[1],o),c(t.IDENT))}else(n=t.IDENT.exec(r))&&(l=!0,s.push(n[1],"_"),c(t.IDENT));return l}for(;a<r.length;)l();return s}(r))},y=/\[([\w-]+)(?:(.?=)"?([^\]]*?)"?)?\]/i,A=/:(?:first|last|nth|only|not|empty)\b/;var N=function(e){return!0};return function(e){for(var r=i(e.html,!e.keepText),n=e.shouldDrop||N,t=v(e.css.replace(c,"")),a={},s=0;s<t.length;s++)if(t[s]===d){var l=t[s+1],m=l[l.length-1];s++;for(var g=0;g<m.length;g++){var b=m[g];e:for(var T=0;T<b.length;T++){var k=b[T],w=!1,_=void 0;if(""!=k){if(k in a)w=a[k];else switch(k[0]){case"#":_=k.substr(1),a[k]=w=r.attr.has("[id="+_+"]");break;case".":_=k.substr(1),a[k]=w=r.class.has(_);break;case"[":if(k.startsWith("[type="))a[k]=w=r.attr.has(k);else{var L=k.match(y);a[k]=w=r.nodes.some(function(e){return x(e,L[1],L[3],L[2])})}break;default:a[k]=w=r.tag.has(k)}if(!w){!0===n(l[g])?l[g]=null:a[l[g]]=!0;break e}}}}}for(var I=0;I<t.length;I++)t[I]===d&&(t[++I].length,t[I]=t[I].filter(function(e){if("string"==typeof e){if(e in a)return a[e];var t=(s=e).replace(/:?:[a-z-]+/gm,function(e){return s.startsWith("::")||!A.test(e)?"":e}).replace(/:[a-z-]+\(\)/gm,"");return""==t||(t in a?a[t]:a[t]=E(r.nodes,t)||!0!==n(e))}var s;return!1}));var D=function(e){for(var r="",n=0,t=0;t<e.length;t++)switch(e[t]){case d:var a=e[++t];(n=a.length)>0&&(r+=a.join());break;case f:n>0&&(r+="{"+e[++t]+"}");break;case u:r+=e[++t]+"{";break;case o:r+="}";break;case h:r+=e[++t]}return r.replace(/@[a-z-]+\s+[^{]+\{\s*\}/gm,"")}(t);return{css:D=function(e){for(var r,n=[],t=new Set,a=/@(?:-\w+-)?keyframes\s+([\w-]+)\s*\{/gm;r=a.exec(e);){var s=p(e,a.lastIndex);n.push([r.index,r[0].length+s.length+1,r[1]])}for(var i=/animation(?:-name)?:([^;!}]+)/gm;r=i.exec(e);)r[1].trim().split(",").forEach(function(e){t.add(e.trim().match(/^[\w-]+/)[0])});for(var c,l,u,o,d=e,f=n.length-1;f>-1;f--){var h=n[f];t.has(h[2])||(c=d,l=h[0],u=h[1],o="",d=c.slice(0,l)+o+c.slice(l+u))}return d}(D)}}});
/*! https://github.com/leeoniya/dropcss (v1.0.0) */
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).dropcss=t()}(this,function(){"use strict";var e=1,t=2,r=3,n=new Set("area base br col command embed hr img input keygen link meta param source track wbr".split(" ")),a=/<!doctype[^>]*>|<!--[\s\S]*?-->|<script[^>]*>[\s\S]*?<\/script>|<style[^>]*>[\s\S]*?<\/style>|<link[^>]*>|<meta[^>]*>/gim,s=/([\w-]+)(?:="([^"]*)"|='([^']*)'|=(\S+))?/gm,i={TAG_HEAD:/\s*<([a-z0-9_-]+)(?:\s+([^>]*))?>\s*/my,TEXT:/\s*[^<]*/my,TAG_CLOSE:/\s*<\/[a-z0-9_-]+>\s*/my};var c=new Set;function o(e,t,r){return{tagName:t,attributes:r,classList:null!=r&&r.has("class")?new Set(r.get("class").split(/\s+/g)):c,parentNode:e,childNodes:[]}}function l(e,t){if(null!=e){var r=e._ofTypes=e._ofTypes||{};if(!(t in r)){var n=0;r[t]=e.childNodes.filter(function(e){if(e.tagName==t)return e._typeIdx=n++,!0})}return r[t]}return null}var u=function(l){var u=function(a){var c,o=0,l=[];function u(e){for(var t in o=e.lastIndex,i)i[t].lastIndex=o}function d(){if(null!=(c=i.TAG_CLOSE.exec(a)))return u(i.TAG_CLOSE),void l.push(r);if(null==(c=i.TAG_HEAD.exec(a)))null!=(c=i.TEXT.exec(a))&&u(i.TEXT);else{u(i.TAG_HEAD);var o=c[1];l.push(e,o);var d=c[2];if(null!=d){for(var f,h=new Map;f=s.exec(d);)h.set(f[1],(f[2]||f[3]||f[4]||"").trim());l.push(t,h)}n.has(o)&&l.push(r)}}for(;o<a.length;)d();return u({lastIndex:0}),l}(l=l.replace(a,"")),d={nodes:[],tag:new Set(["*"]),class:new Set,attr:new Set};!function(n,a){for(var s,i=o(null,"root",c),l=0;l<n.length;l++)switch(n[l]){case e:var u=n[++l],d=c;n[l+1]===t&&(d=n[l+=2]),s=i.childNodes.length,i.childNodes.push(i=o(i,u,d)),a(i,s);break;case r:i=i.parentNode}}(u,function(e,t){return function(e,t,r){e.idx=t;var n=e.attributes;r.tag.add(e.tagName),e.classList.forEach(function(e){return r.class.add(e)}),n.has("id")&&r.attr.add("[id="+n.get("id")+"]"),n.has("type")&&r.attr.add("[type="+n.get("type")+"]"),r.nodes.push(e)}(e,t,d)});return d},d=/\s*\/\*[\s\S]*?\*\/\s*/gm,f=/\s*[>~+]\s*|\s+/g,h=1,p=2,x=3,v=4,m=5;function g(e,t){for(var r="",n=1;"{"==e[t]?n++:"}"==e[t]&&n--,0!=n;)r+=e[t++];return r}function y(e){var t,r={RULE_HEAD:/\s*([^{;]+?)\s*[{;]\s*/my,RULE_TAIL:/\s*([^}]*?)\s*\}/my,AT_TAIL:/\s*\}/my,RULE_FULL:/\s*([^{]*?)\{([^}]+?)\}/my},n=0,a=0,s=[];function i(e){for(var t in a=e.lastIndex,r)r[t].lastIndex=a}function c(){if(n>0&&null!=(t=r.AT_TAIL.exec(e)))return n--,s.push(p),void i(r.AT_TAIL);if(null!=(t=r.RULE_HEAD.exec(e))){var c=t[1];if(i(r.RULE_HEAD),"@"==c[0])switch(c.match(/@[a-z-]+/)[0]){case"@media":case"@supports":case"@document":n++,s.push(h,c);break;case"@import":case"@charset":case"@namespace":s.push(m,c+";");break;default:n++;var o=g(e,a);i({lastIndex:a+o.length}),s.push(h,c,m,o)}else s.push(x,(l=t[1],(u=l.split(/\s*,\s*/gm)).push(u.map(function(e){return function(e){return e.replace(/:?:[a-z-]+(?:\([^()]+\))?/gm,"")}(e).trim().replace(/(\.|#|\[)/gm," $1").replace(/\]/gm,"] ").trim().split(f)})),u)),t=r.RULE_TAIL.exec(e),s.push(v,t[1]),i(r.RULE_TAIL)}else a=e.length;var l,u}for(;a<e.length;)c();return s}function b(e,t){return t==e.tagName||"*"==t}function k(e,t,r,n){n=n||"=";var a=e.attributes;if(a.has(t)){var s=a.get(t);switch(n){case"=":return null==r||r==s;case"*=":return-1!=s.indexOf(r);case"^=":return s.startsWith(r);case"$=":return s.endsWith(r)}}return!1}function T(e,t){return e.classList.has(t)}function E(e,t){return e.some(function(e){return function e(t,r){var n,a,s,i,c,o;for(;r.idx>-1;){switch(t[r.idx]){case"_":n=t[--r.idx],o=b(r.node,n),r.idx--;break;case"#":a=t[--r.idx],o=k(r.node,"id",a,"="),r.idx--;break;case".":n=t[--r.idx],o=T(r.node,n),r.idx--;break;case"[":n=t[--r.idx],s=t[--r.idx],a=t[--r.idx],o=k(r.node,n,a,s),r.idx--;break;case":":n=t[--r.idx],a=t[--r.idx];var u=r.node,d=u.tagName;c=u.idx;var f=(i=u.parentNode)?i.childNodes.length:1,h=void 0;switch(n){case"not":o=!e(a,{node:r.node,idx:a.length-1});break;case"first-child":o=0==c;break;case"last-child":o=c==f-1;break;case"only-child":o=1==f;break;case"nth-child":o=w(c+1,a);break;case"nth-last-child":o=w(f-c,a);break;case"first-of-type":h=l(i,d),o=0==u._typeIdx;break;case"last-of-type":h=l(i,d),o=u._typeIdx==h.length-1;break;case"only-of-type":h=l(i,d),o=1==h.length;break;case"nth-of-type":h=l(i,d),o=w(u._typeIdx+1,a);break;case"nth-last-of-type":h=l(i,d),o=w(h.length-u._typeIdx,a)}r.idx--;break;case" ":for(c=--r.idx,o=!1;!o&&null!=(i=r.node.parentNode);)r.idx=c,r.node=i,o=e(t,r);break;case">":r.idx--,null!=(i=r.node.parentNode)?(r.node=i,o=e(t,r)):o=!1;break;case"+":r.idx--,null!=(i=r.node.parentNode)&&r.node.idx>0?(r.node=i.childNodes[r.node.idx-1],o=e(t,r)):o=!1;break;case"~":if(r.idx--,o=!1,c=r.node.idx,null!=(i=r.node.parentNode)&&c>0)for(var p=0;p<c&&!o;p++)r.node=i.childNodes[p],o=e(t,r)}if(!o)break}return o}(t,{idx:t.length-1,node:e})})}var _=/^([+-]?\d*)?n([+-]\d+)?$/;function w(e,t){var r;if("odd"==t)r=e%2==1;else if("even"==t)r=e%2==0;else if(/^\d+$/.test(t))r=e==+t;else{var n=function(e){var t=_.exec(e);if(null!=t){var r=t[1],n=t[2];return[r=null==r||"+"==r?1:"-"==r?-1:+r,n=null==n?0:+n]}return[0,0]}(t);r=function(e,t,r){if(t<0&&e<=0)return!1;if(-1===e)return r<=t;if(0===e)return r===t;if(1===e)return t<0||r>=t;var n=t%e;return n<0&&(n+=e),e>1?r>=t&&r%e===n:(e*=-1,r<=t&&r%e===n)}(n[0],n[1],e)}return r}var A=function(e,t){return E(e,Array.isArray(t)?t:function e(t){var r,n={IDENT:/([\w*-]+)/iy,ATTR:/([\w-]+)(?:(.?=)"?([^\]]*?)"?)?\]/iy,PSEUDO:/([\w-]+)(?:\(([^)]*)\))?/iy,MODE:/\s*[:.#\[]\s*/iy,COMB:/\s*[>~+]\s*|\s+/iy},a=0,s=[],i=-1;function c(e){for(var t in a=e.lastIndex,n)n[t].lastIndex=a}function o(){var o=!1;if(r=n.COMB.exec(t)){o=!0;var l=r[0].trim();""==l&&(l=" "),s.push(l),c(n.COMB),i=a}else if(r=n.MODE.exec(t)){o=!0;var u=r[0].trim();c(n.MODE),":"==u?(r=n.PSEUDO.exec(t),s.splice(i+1,0,null!=r[2]&&"not"==r[1]?e(r[2]):r[2],r[1],u),c(n.PSEUDO)):"["==u?(r=n.ATTR.exec(t),s.splice(i+1,0,r[3],r[2],r[1],u),c(n.ATTR)):(r=n.IDENT.exec(t),s.push(r[1],u),c(n.IDENT))}else(r=n.IDENT.exec(t))&&(o=!0,s.push(r[1],"_"),c(n.IDENT));return o}for(;a<t.length;)o();return s}(t))},I=/\[([\w-]+)(?:(.?=)"?([^\]]*?)"?)?\]/i,N=/:(?:first|last|nth|only|not)\b/;function L(e,t,r){for(var n=t.length-1;n>-1;n--){var a=t[n];r.has(a[2])||(s=e,i=a[0],c=a[1],o="",e=s.slice(0,i)+o+s.slice(i+c))}var s,i,c,o;return e}var S=function(e){return!0};return function(e){for(var t=u(e.html,!e.keepText),r=e.shouldDrop||S,n=y(e.css.replace(d,"")),a={},s=0;s<n.length;s++)if(n[s]===x){var i=n[s+1],c=i[i.length-1];s++;for(var o=0;o<c.length;o++){var l=c[o];e:for(var f=0;f<l.length;f++){var b=l[f],T=!1,E=void 0;if(""!=b){if(b in a)T=a[b];else switch(b[0]){case"#":E=b.substr(1),a[b]=T=t.attr.has("[id="+E+"]");break;case".":E=b.substr(1),a[b]=T=t.class.has(E);break;case"[":if(b.startsWith("[type="))a[b]=T=t.attr.has(b);else{var _=b.match(I);a[b]=T=t.nodes.some(function(e){return k(e,_[1],_[3],_[2])})}break;default:a[b]=T=t.tag.has(b)}if(!T){!0===r(i[o])?i[o]=null:a[i[o]]=!0;break e}}}}}for(var w=0;w<n.length;w++)n[w]===x&&(n[++w].length,n[w]=n[w].filter(function(e){if("string"==typeof e){if(e in a)return a[e];var n=(s=e).replace(/:?:[a-z-]+/gm,function(e){return s.startsWith("::")||!N.test(e)?"":e}).replace(/:[a-z-]+\(\)/gm,"");return""==n||(n in a?a[n]:a[n]=A(t.nodes,n)||!0!==r(e))}var s;return!1}));var D=function(e){for(var t="",r=0,n=0;n<e.length;n++)switch(e[n]){case x:var a=e[++n];(r=a.length)>0&&(t+=a.join());break;case v:r>0&&(t+="{"+e[++n]+"}");break;case h:t+=e[++n]+"{";break;case p:t+="}";break;case m:t+=e[++n]}return t.replace(/@[a-z-]+\s+[^{]+\{\s*\}/gm,"")}(n);return{css:D=function(e){for(var t,r=[],n=new Set,a=/@font-face[\s\S]+?font-family:\s*(['"\w-]+)[^}]+\}/gm;t=a.exec(e);){var s=t[1].replace(/['"]/gm,"");r.push([t.index,t[0].length,s])}for(var i=/font-family:([^;!}]+)/gm;t=i.exec(e);)r.some(function(e){return t.index>e[0]&&t.index<e[0]+e[1]})||t[1].trim().split(",").forEach(function(e){n.add(e.trim().replace(/['"]/gm,""))});return L(e,r,n)}(D=function(e){for(var t,r=[],n=new Set,a=/@(?:-\w+-)?keyframes\s+([\w-]+)\s*\{/gm;t=a.exec(e);){var s=g(e,a.lastIndex);r.push([t.index,t[0].length+s.length+1,t[1]])}for(var i=/animation(?:-name)?:([^;!}]+)/gm;t=i.exec(e);)t[1].trim().split(",").forEach(function(e){n.add(e.trim().match(/^[\w-]+/)[0])});return L(e,r,n)}(D))}}});
{
"name": "dropcss",
"version": "0.5.0",
"version": "1.0.0",
"description": "An exceptionally fast, thorough and tiny unused-CSS cleaner",

@@ -28,3 +28,3 @@ "main": "./dist/dropcss.cjs.js",

"devDependencies": {
"mocha": "^6.0.2",
"mocha": "^6.1.2",
"nyc": "^13.3.0",

@@ -31,0 +31,0 @@ "rollup": "^1.9.0",

@@ -8,5 +8,5 @@ ## ๐Ÿ—‘ DropCSS

DropCSS is an exceptionally fast, thorough and tiny ([~7.5 KB min](https://github.com/leeoniya/dropcss/tree/master/dist/dropcss.min.js)) unused-CSS cleaner; it takes your HTML and CSS as input and returns only the used CSS as output. Its custom HTML and CSS parsers are highly optimized for the 99% use case and thus avoid the overhead of handling malformed markup or stylesheets, so you must provide well-formed input. There is minimal handling for complex escaping rules, so there will always exist cases of valid input that cannot be processed by DropCSS; for these infrequent cases, please [start a discussion](https://github.com/leeoniya/dropcss/issues), use a previous, larger and slower [0.3.x version](https://github.com/leeoniya/dropcss/releases) that uses heavier but more compliant parsers, or use an alternative CSS cleaner.
DropCSS is an exceptionally fast, thorough and tiny ([~8 KB min](https://github.com/leeoniya/dropcss/tree/master/dist/dropcss.min.js)) unused-CSS cleaner; it takes your HTML and CSS as input and returns only the used CSS as output. Its custom HTML and CSS parsers are highly optimized for the 99% use case and thus avoid the overhead of handling malformed markup or stylesheets, so you must provide well-formed input. There is minimal handling for complex escaping rules, so there will always exist cases of valid input that cannot be processed by DropCSS; for these infrequent cases, please [start a discussion](https://github.com/leeoniya/dropcss/issues), use a previous, larger and slower [0.3.x version](https://github.com/leeoniya/dropcss/releases) that uses heavier but more compliant parsers, or use an alternative CSS cleaner.
It is recommended to also run your CSS through a structural optimizer like [clean-css](https://github.com/jakubpawlowicz/clean-css), [csso](https://github.com/css/csso), [cssnano](https://github.com/cssnano/cssnano) or [crass](https://github.com/mattbasta/crass) to group selectors, merge and remove redundant rules, purge unused keyframes, etc.
As a bonus, DropCSS will also remove unused any `@keyframes` and `@font-face` blocks, despite it being somewhat out of scope for this lib (being a purely intra-CSS optimization). Speaking of which, it's a good idea to run your CSS through a structural optimizer like [clean-css](https://github.com/jakubpawlowicz/clean-css), [csso](https://github.com/css/csso), [cssnano](https://github.com/cssnano/cssnano) or [crass](https://github.com/mattbasta/crass) to re-group selectors, merge redundant rules, etc. It probably makes sense to do this after DropCSS, which can leave redundant blocks, e.g. `.foo, .bar { color: red; }; .bar { width: 50%; }` -> `.bar { color: red; }; .bar { width: 50%; }` if `.foo` is absent from your markup.

@@ -16,2 +16,5 @@ A bit more on this project's backstory & discussions in [/r/javascript](https://old.reddit.com/r/javascript/comments/b3mcu8/dropcss_010_a_minimal_and_thorough_unused_css/) and on [Hacker News](https://news.ycombinator.com/item?id=19469080).

---
<h3 align="center">Live Demo: <a href="https://codepen.io/leeoniya/pen/LvbRyq">https://codepen.io/leeoniya/pen/LvbRyq</a></h3>
---
### Installation

@@ -55,3 +58,2 @@

css,
keepText: false,
shouldDrop: (sel) => {

@@ -72,4 +74,3 @@ if (whitelist.test(sel))

- `shouldDrop` is called for every CSS selector that could not be matched in the `html`. Return `false` to retain the selector or `true` to drop it. Additionally, this hook can be used to log all removed selectors.
- `keepText` - By default, DropCSS will remove all text nodes from the HTML before processing further since very few CSS selectors can actually target text. Not having to process text nodes is a significant performance boost. However, a few uncommon pseudo-classes like `:blank` and `:empty` do assert on text nodes. If combined as e.g. `:not(:empty)`, this could result wrongful removal, or wrongful retention of selectors. Setting `keepText` to `true` will leave all text nodes in place to allow for this to work properly at the expense of performance.
The `shouldDrop` hook is called for every CSS selector that could not be matched in the `html`. Return `false` to retain the selector or `true` to drop it.

@@ -95,3 +96,2 @@ ---

- `:not()`
- `:empty`
- `:first-child`

@@ -102,2 +102,7 @@ - `:last-child`

- `:nth-last-child()`
- `:first-of-type`
- `:last-of-type`
- `:only-of-type`
- `:nth-of-type()`
- `:nth-last-of-type()`

@@ -191,12 +196,4 @@ ---

- All `-of-type` selectors are currently unimplemented, so will not be removed unless already disqualified by a paired selector, (e.g. `.card:first-of-type` when `.card` is absent altogether). This is pretty easy to implement and a good first issue for those interested in contributing: [Issue #4](https://github.com/leeoniya/dropcss/issues/4).
- `:first-of-type`
- `:last-of-type`
- `:only-of-type`
- `:nth-of-type()`
- `:nth-last-of-type()`
- `:nth-only-of-type()`
- Moar tests. DropCSS is currently developed against gigantic blobs of diverse, real-world CSS and HTML. These inputs & outputs are also used for perf testing and regression detection. While not all output was verified by hand (this would be infeasible for giganitic mis-matched HTML/CSS inputs), it was loosely verified against what other cleaners remove and what they leave behind. Writing tests is additonally challenging because the way selectors are drop-tested is optimized to fast-path many cases; a complex-looking test like `.foo > ul + p:not([foo*=bar]):hover` will actually short circuit early if `.foo`, `ul` or `p` are missing from the dom, and will never continue to structural/context or negation assertions. Tests must be carefully written to ensure they hit all the desired paths; it's easy to waste a lot of time writing useless tests that add no value. Unfortunately, even 100% cumulative code coverage of the test suite would only serve as a starting point. Good tests would be a diverse set of real-world inputs and manually verified outputs.
- Moar tests. Hundreds of additional, granular tests. DropCSS is currently developed against gigantic blobs of diverse, real-world CSS and HTML. These inputs & outputs are also used for perf testing and regression detection. While not all output was verified by hand (this would be infeasible for giganitic mis-matched HTML/CSS inputs), it was loosely verified against what other cleaners remove and what they leave behind. Writing tests is additonally challenging because the way selectors are drop-tested is optimized to fast-path many cases; a complex-looking test like `.foo > ul + p:not([foo*=bar]):hover` will actually short circuit early if `.foo`, `ul` or `p` are missing from the dom, and will never continue to structural/context or negation assertions. Tests must be carefully written to ensure they hit all the desired paths; it's easy to waste a lot of time writing useless tests that add no value. Unfortunately, even 100% cumulative code coverage of the test suite would only serve as a starting point. Good tests would be a diverse set of real-world inputs and manually verified outputs.
---

@@ -203,0 +200,0 @@ ### Caveats

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with โšก๏ธ by Socket Inc