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

purgecss

Package Overview
Dependencies
Maintainers
2
Versions
64
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

purgecss - npm Package Compare versions

Comparing version 1.1.0 to 1.2.0

8

CHANGELOG.md
# Changelog
# v1.2.0 - 2019-04-05
* fix issue https://github.com/FullHuman/purgecss/issues/148, so the default extract is used for any file type that is not specified
* Merged https://github.com/FullHuman/purgecss/pull/167, fixing issue #166
* Merged https://github.com/FullHuman/purgecss/pull/176, fixing invalid json output by the CLI
* Update dependencies
* Update dev dependencies, including babel 7
# v1.1.0 - 2018-08-21

@@ -4,0 +12,0 @@

1437

lib/purgecss.es.js

@@ -6,2 +6,73 @@ import fs from 'fs';

function _typeof(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function (obj) {
return typeof obj;
};
} else {
_typeof = function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
}
}
function _iterableToArray(iter) {
if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance");
}
// Copyright Joyent, Inc. and other Node contributors.

@@ -27,3 +98,2 @@ //

// USE OR OTHER DEALINGS IN THE SOFTWARE.
// resolves . and .. elements in a path array with directory names there

@@ -36,4 +106,6 @@ // must be no slashes, empty elements, or device names (c:\) in the array

var up = 0;
for (var i = parts.length - 1; i >= 0; i--) {
var last = parts[i];
if (last === '.') {

@@ -48,5 +120,5 @@ parts.splice(i, 1);

}
}
} // if the path is allowed to go above the root, restore leading ..s
// if the path is allowed to go above the root, restore leading ..s
if (allowAboveRoot) {

@@ -59,13 +131,14 @@ for (; up--; up) {

return parts;
}
} // Split a filename into [root, dir, basename, ext], unix version
// 'root' is just a slash, or nothing.
// Split a filename into [root, dir, basename, ext], unix version
// 'root' is just a slash, or nothing.
var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
var splitPath = function splitPath(filename) {
var splitPath = function (filename) {
return splitPathRe.exec(filename).slice(1);
};
}; // path.resolve([from ...], to)
// posix version
// path.resolve([from ...], to)
// posix version
function resolve() {

@@ -76,5 +149,4 @@ var resolvedPath = '',

for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
var path = i >= 0 ? arguments[i] : '/';
var path = i >= 0 ? arguments[i] : '/'; // Skip empty and invalid entries
// Skip empty and invalid entries
if (typeof path !== 'string') {

@@ -88,21 +160,18 @@ throw new TypeError('Arguments to path.resolve must be strings');

resolvedAbsolute = path.charAt(0) === '/';
}
// At this point the path should be resolved to a full absolute path, but
} // At this point the path should be resolved to a full absolute path, but
// handle relative paths to be safe (might happen when process.cwd() fails)
// Normalize the path
// Normalize the path
resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function (p) {
return !!p;
}), !resolvedAbsolute).join('/');
return (resolvedAbsolute ? '/' : '') + resolvedPath || '.';
}
// path.normalize(path)
// posix version
function normalize(path) {
var isPathAbsolute = isAbsolute(path),
trailingSlash = substr(path, -1) === '/';
trailingSlash = substr(path, -1) === '/'; // Normalize the path
// Normalize the path
path = normalizeArray(filter(path.split('/'), function (p) {

@@ -115,2 +184,3 @@ return !!p;

}
if (path && trailingSlash) {

@@ -122,8 +192,7 @@ path += '/';

}
// posix version
function isAbsolute(path) {
return path.charAt(0) === '/';
}
} // posix version
// posix version
function join() {

@@ -135,8 +204,8 @@ var paths = Array.prototype.slice.call(arguments, 0);

}
return p;
}).join('/'));
}
} // path.relative(from, to)
// posix version
// path.relative(from, to)
// posix version
function relative(from, to) {

@@ -148,2 +217,3 @@ from = resolve(from).substr(1);

var start = 0;
for (; start < arr.length; start++) {

@@ -154,2 +224,3 @@ if (arr[start] !== '') break;

var end = arr.length - 1;
for (; end >= 0; end--) {

@@ -165,5 +236,5 @@ if (arr[end] !== '') break;

var toParts = trim(to.split('/'));
var length = Math.min(fromParts.length, toParts.length);
var samePartsLength = length;
for (var i = 0; i < length; i++) {

@@ -177,2 +248,3 @@ if (fromParts[i] !== toParts[i]) {

var outputParts = [];
for (var i = samePartsLength; i < fromParts.length; i++) {

@@ -183,9 +255,6 @@ outputParts.push('..');

outputParts = outputParts.concat(toParts.slice(samePartsLength));
return outputParts.join('/');
}
var sep = '/';
var delimiter = ':';
function dirname(path) {

@@ -208,12 +277,11 @@ var result = splitPath(path),

}
function basename(path, ext) {
var f = splitPath(path)[2]; // TODO: make this comparison case-insensitive on windows?
function basename(path, ext) {
var f = splitPath(path)[2];
// TODO: make this comparison case-insensitive on windows?
if (ext && f.substr(-1 * ext.length) === ext) {
f = f.substr(0, f.length - ext.length);
}
return f;
}
function extname(path) {

@@ -234,12 +302,15 @@ return splitPath(path)[3];

};
function filter(xs, f) {
if (xs.filter) return xs.filter(f);
var res = [];
for (var i = 0; i < xs.length; i++) {
if (f(xs[i], i, xs)) res.push(xs[i]);
}
return res;
}
} // String.prototype.substr - negative index don't work in IE8
// String.prototype.substr - negative index don't work in IE8
var substr = 'ab'.substr(-1) === 'b' ? function (str, start, len) {

@@ -253,13 +324,12 @@ return str.substr(start, len);

//
var defaultOptions = {
css: [],
content: [],
extractors: [],
whitelist: [],
output: undefined,
stdout: false,
keyframes: false,
fontFace: false,
rejected: false
css: [],
content: [],
extractors: [],
whitelist: [],
output: undefined,
stdout: false,
keyframes: false,
fontFace: false,
rejected: false
};

@@ -270,5 +340,4 @@

var IGNORE_ANNOTATION_END = 'purgecss end ignore';
var CONFIG_FILENAME = 'purgecss.config.js';
var CONFIG_FILENAME = 'purgecss.config.js'; // Error Message
// Error Message
var ERROR_CONFIG_FILE_LOADING = 'Error loading the config file';

@@ -278,10 +347,7 @@ var ERROR_MISSING_CONTENT = 'No content provided.';

var ERROR_EXTRACTER_FAILED = 'The extractor has failed to extract the selectors.';
var ERROR_OPTIONS_TYPE = 'Error Type Options: expected an object';
var ERROR_OUTPUT_TYPE = 'Error Type option output: expected a string';
var ERROR_EXTRACTERS_TYPE = 'Error Type option extractors: expected an array';
var ERROR_WHITELIST_TYPE = 'Error Type option whitelist: expected an array';
var ERROR_WHITELIST_PATTERNS_TYPE = 'Error Type option whitelistPatterns: expected an array';
var ERROR_STDOUT_TYPE = 'Error Type option stdout: expected a boolean';

@@ -293,778 +359,721 @@

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
return typeof obj;
} : function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
var classCallCheck = function (instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
var DefaultExtractor =
/*#__PURE__*/
function () {
function DefaultExtractor() {
_classCallCheck(this, DefaultExtractor);
}
};
var createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
_createClass(DefaultExtractor, null, [{
key: "extract",
value: function extract(content) {
return content.match(/[A-Za-z0-9_-]+/g) || [];
}
}
}]);
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
return DefaultExtractor;
}();
var toConsumableArray = function (arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
var Purgecss =
/*#__PURE__*/
function () {
function Purgecss(options) {
_classCallCheck(this, Purgecss);
return arr2;
} else {
return Array.from(arr);
_defineProperty(this, "atRules", {
keyframes: [],
fontFace: []
});
_defineProperty(this, "usedAnimations", new Set());
_defineProperty(this, "usedFontFaces", new Set());
_defineProperty(this, "selectorsRemoved", new Set());
_defineProperty(this, "ignore", false);
if (typeof options === 'string' || typeof options === 'undefined') options = this.loadConfigFile(options);
this.checkOptions(options);
this.options = Object.assign(defaultOptions, options);
}
};
/**
* Load the configuration file from the path
* @param {string} configFile Path of the config file
*/
var DefaultExtractor = function () {
function DefaultExtractor() {
classCallCheck(this, DefaultExtractor);
}
createClass(DefaultExtractor, null, [{
key: "extract",
value: function extract(content) {
return content.match(/[A-Za-z0-9_-]+/g) || [];
}
}]);
return DefaultExtractor;
}();
_createClass(Purgecss, [{
key: "loadConfigFile",
value: function loadConfigFile(configFile) {
var pathConfig = typeof configFile === 'undefined' ? CONFIG_FILENAME : configFile;
var options;
//
try {
var t = path.resolve(process.cwd(), pathConfig);
options = require(t);
} catch (e) {
throw new Error(ERROR_CONFIG_FILE_LOADING + e.message);
}
var Purgecss = function () {
function Purgecss(options) {
classCallCheck(this, Purgecss);
this.atRules = {
keyframes: [],
fontFace: []
};
this.usedAnimations = new Set();
this.usedFontFaces = new Set();
this.selectorsRemoved = new Set();
this.ignore = false;
return options;
}
/**
* Verify that the purgecss options provided are valid
* @param {object} options Purgecss options
*/
if (typeof options === 'string' || typeof options === 'undefined') options = this.loadConfigFile(options);
this.checkOptions(options);
this.options = Object.assign(defaultOptions, options);
}, {
key: "checkOptions",
value: function checkOptions(options) {
if (_typeof(options) !== 'object') throw new TypeError(ERROR_OPTIONS_TYPE);
if (!options.content || !options.content.length) throw new Error(ERROR_MISSING_CONTENT);
if (!options.css || !options.css.length) throw new Error(ERROR_MISSING_CSS);
if (options.output && typeof options.output !== 'string') throw new TypeError(ERROR_OUTPUT_TYPE);
if (options.extractors && !Array.isArray(options.extractors)) throw new TypeError(ERROR_EXTRACTERS_TYPE);
if (options.whitelist && !Array.isArray(options.whitelist)) throw new TypeError(ERROR_WHITELIST_TYPE);
if (options.stdout && typeof options.stdout !== 'boolean') throw new TypeError(ERROR_STDOUT_TYPE);
if (options.whitelistPatterns && !Array.isArray(options.whitelistPatterns)) throw new TypeError(ERROR_WHITELIST_PATTERNS_TYPE);
}
/**
* Main function that purge the css file
*/
}, {
key: "purge",
value: function purge() {
// Get selectors from content files
var _this$options = this.options,
content = _this$options.content,
extractors = _this$options.extractors,
css = _this$options.css;
var fileFormatContents = content.filter(function (o) {
return typeof o === 'string';
});
var rawFormatContents = content.filter(function (o) {
return _typeof(o) === 'object';
});
var cssFileSelectors = this.extractFileSelector(fileFormatContents, extractors);
var cssRawSelectors = this.extractRawSelector(rawFormatContents, extractors); // Get css selectors and remove unused ones
return this.getCssContents(css, new Set([].concat(_toConsumableArray(cssFileSelectors), _toConsumableArray(cssRawSelectors))));
}
/**
* Load the configuration file from the path
* @param {string} configFile Path of the config file
* Get the content of the css files, or return the raw content
* @param {array} cssOptions Array of css options, files and raw
* @param {Set} cssSelectors Set of all extracted css selectors
*/
}, {
key: "getCssContents",
value: function getCssContents(cssOptions, cssSelectors) {
var sources = []; // resolve any globs and flatten again
createClass(Purgecss, [{
key: 'loadConfigFile',
value: function loadConfigFile(configFile) {
var pathConfig = typeof configFile === 'undefined' ? CONFIG_FILENAME : configFile;
var options = void 0;
try {
var t = path.resolve(process.cwd(), pathConfig);
options = require(t);
} catch (e) {
throw new Error(ERROR_CONFIG_FILE_LOADING + e.message);
}
return options;
}
cssOptions = cssOptions.map(function (option) {
return typeof option === 'string' ? glob.sync(option) : option;
});
cssOptions = [].concat.apply([], cssOptions);
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
/**
* Verify that the purgecss options provided are valid
* @param {object} options Purgecss options
*/
try {
for (var _iterator = cssOptions[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var option = _step.value;
var file = null;
var rejected = null;
var cssContent = '';
}, {
key: 'checkOptions',
value: function checkOptions(options) {
if ((typeof options === 'undefined' ? 'undefined' : _typeof(options)) !== 'object') throw new TypeError(ERROR_OPTIONS_TYPE);
if (!options.content || !options.content.length) throw new Error(ERROR_MISSING_CONTENT);
if (!options.css || !options.css.length) throw new Error(ERROR_MISSING_CSS);
if (options.output && typeof options.output !== 'string') throw new TypeError(ERROR_OUTPUT_TYPE);
if (options.extractors && !Array.isArray(options.extractors)) throw new TypeError(ERROR_EXTRACTERS_TYPE);
if (options.whitelist && !Array.isArray(options.whitelist)) throw new TypeError(ERROR_WHITELIST_TYPE);
if (options.stdout && typeof options.stdout !== 'boolean') throw new TypeError(ERROR_STDOUT_TYPE);
if (options.whitelistPatterns && !Array.isArray(options.whitelistPatterns)) throw new TypeError(ERROR_WHITELIST_PATTERNS_TYPE);
}
if (typeof option === 'string') {
file = option;
cssContent = this.options.stdin ? file : fs.readFileSync(file, 'utf8');
} else {
cssContent = option.raw;
}
/**
* Main function that purge the css file
*/
this.root = postcss.parse(cssContent); // purge selectors
}, {
key: 'purge',
value: function purge() {
// Get selectors from content files
var _options = this.options,
content = _options.content,
extractors = _options.extractors,
css = _options.css;
this.getSelectorsCss(cssSelectors); // purge keyframes
if (this.options.keyframes) this.removeUnusedKeyframes(); // purge font face
var fileFormatContents = content.filter(function (o) {
return typeof o === 'string';
});
var rawFormatContents = content.filter(function (o) {
return (typeof o === 'undefined' ? 'undefined' : _typeof(o)) === 'object';
});
if (this.options.fontFace) this.removeUnusedFontFaces();
var purgeResult = {
file: file,
css: this.root.toString(),
rejected: rejected
};
var cssFileSelectors = this.extractFileSelector(fileFormatContents, extractors);
var cssRawSelectors = this.extractRawSelector(rawFormatContents, extractors);
if (this.options.rejected) {
rejected = Array.from(this.selectorsRemoved);
this.selectorsRemoved.clear();
}
// Get css selectors and remove unused ones
return this.getCssContents(css, new Set([].concat(toConsumableArray(cssFileSelectors), toConsumableArray(cssRawSelectors))));
purgeResult.rejected = rejected;
sources.push(purgeResult);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
/**
* Get the content of the css files, or return the raw content
* @param {array} cssOptions Array of css options, files and raw
* @param {Set} cssSelectors Set of all extracted css selectors
*/
return sources;
}
/**
* Remove Keyframes that were never used
*/
}, {
key: 'getCssContents',
value: function getCssContents(cssOptions, cssSelectors) {
var sources = [];
}, {
key: "removeUnusedKeyframes",
value: function removeUnusedKeyframes() {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
// resolve any globs and flatten again
cssOptions = cssOptions.map(function (option) {
return typeof option === 'string' ? glob.sync(option) : option;
});
cssOptions = [].concat.apply([], cssOptions);
try {
for (var _iterator2 = this.atRules.keyframes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var node = _step2.value;
var nodeName = node.params;
var used = this.usedAnimations.has(nodeName);
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
if (!used) {
node.remove();
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
/**
* Remove Font-Faces that were never used
*/
try {
for (var _iterator = cssOptions[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var option = _step.value;
}, {
key: "removeUnusedFontFaces",
value: function removeUnusedFontFaces() {
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
var file = null;
var rejected = null;
var cssContent = '';
if (typeof option === 'string') {
file = option;
cssContent = this.options.stdin ? file : fs.readFileSync(file, 'utf8');
} else {
cssContent = option.raw;
}
try {
for (var _iterator3 = this.atRules.fontFace[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var _step3$value = _step3.value,
node = _step3$value.node,
name = _step3$value.name;
var used = this.usedFontFaces.has(name);
this.root = postcss.parse(cssContent);
if (!used) {
node.remove();
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
}
/**
* Extract the selectors present in the passed string using a purgecss extractor
* @param {array} content Array of content
* @param {array} extractors Array of extractors
*/
// purge selectors
this.getSelectorsCss(cssSelectors);
}, {
key: "extractRawSelector",
value: function extractRawSelector(content, extractors) {
var selectors = new Set();
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
// purge keyframes
if (this.options.keyframes) this.removeUnusedKeyframes();
try {
for (var _iterator4 = content[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var _step4$value = _step4.value,
raw = _step4$value.raw,
extension = _step4$value.extension;
var extractor = this.getFileExtractor(".".concat(extension), extractors);
selectors = new Set([].concat(_toConsumableArray(selectors), _toConsumableArray(this.extractSelectors(raw, extractor))));
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return != null) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
// purge font face
if (this.options.fontFace) this.removeUnusedFontFaces();
return selectors;
}
/**
* Extract the selectors present in the files using a purgecss extractor
* @param {array} files Array of files path or glob pattern
* @param {array} extractors Array of extractors
*/
var purgeResult = {
file: file,
css: this.root.toString(),
rejected: rejected
};
}, {
key: "extractFileSelector",
value: function extractFileSelector(files, extractors) {
var selectors = new Set();
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
if (this.options.rejected) {
rejected = Array.from(this.selectorsRemoved);
this.selectorsRemoved.clear();
}
try {
for (var _iterator5 = files[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var globfile = _step5.value;
var filesnames = [];
purgeResult.rejected = rejected;
if (fs.existsSync(globfile)) {
filesnames.push(globfile);
} else {
filesnames = glob.sync(globfile);
}
sources.push(purgeResult);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
var _iteratorNormalCompletion6 = true;
var _didIteratorError6 = false;
var _iteratorError6 = undefined;
try {
for (var _iterator6 = filesnames[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
var file = _step6.value;
var content = fs.readFileSync(file, 'utf8');
var extractor = this.getFileExtractor(file, extractors);
selectors = new Set([].concat(_toConsumableArray(selectors), _toConsumableArray(this.extractSelectors(content, extractor))));
}
} catch (err) {
_didIteratorError6 = true;
_iteratorError6 = err;
} finally {
try {
if (!_iteratorNormalCompletion6 && _iterator6.return != null) {
_iterator6.return();
}
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
if (_didIteratorError6) {
throw _iteratorError6;
}
}
return sources;
}
}
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return != null) {
_iterator5.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
}
}
}
/**
* Remove Keyframes that were never used
*/
return selectors;
}
/**
* Get the extractor corresponding to the extension file
* @param {string} filename Name of the file
* @param {array} extractors Array of extractors definition objects
*/
}, {
key: 'removeUnusedKeyframes',
value: function removeUnusedKeyframes() {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
}, {
key: "getFileExtractor",
value: function getFileExtractor(filename) {
var extractors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
if (!extractors.length) return DefaultExtractor;
var extractorObj = extractors.find(function (extractor) {
return extractor.extensions.find(function (ext) {
return filename.endsWith(ext);
});
}) || DefaultExtractor;
return extractorObj.extractor;
}
/**
* Use the extract function of the extractor to get the list of selectors
* @param {string} content Content (e.g: html file)
* @param {object} extractor Purgecss extractor use to extract the selector
*/
try {
for (var _iterator2 = this.atRules.keyframes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var node = _step2.value;
}, {
key: "extractSelectors",
value: function extractSelectors(content, extractor) {
var selectors = new Set();
var arraySelector = typeof extractor.extract === 'undefined' ? extractor(content) : extractor.extract(content);
var nodeName = node.params;
var used = this.usedAnimations.has(nodeName);
if (arraySelector === null) {
throw new Error(ERROR_EXTRACTER_FAILED);
}
if (!used) {
node.remove();
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
arraySelector.forEach(function (selector) {
selectors.add(selector);
}); // Remove empty string
/**
* Remove Font-Faces that were never used
*/
selectors.delete('');
return selectors;
}
/**
* Use postcss to walk through the css ast and remove unused css
* @param {*} selectors selectors used in content files
*/
}, {
key: 'removeUnusedFontFaces',
value: function removeUnusedFontFaces() {
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
}, {
key: "getSelectorsCss",
value: function getSelectorsCss(selectors) {
var _this = this;
try {
for (var _iterator3 = this.atRules.fontFace[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var _ref = _step3.value;
var node = _ref.node;
var name = _ref.name;
this.root.walk(function (node) {
if (node.type === 'rule') {
return _this.evaluateRule(node, selectors);
}
var used = this.usedFontFaces.has(name);
if (node.type === 'atrule') {
return _this.evaluateAtRule(node);
}
if (!used) {
node.remove();
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
if (node.type === 'comment') {
if (_this.isIgnoreAnnotation(node, 'start')) _this.ignore = true;else if (_this.isIgnoreAnnotation(node, 'end')) _this.ignore = false;
}
});
}
/**
* Evaluate css selector and decide if it should be removed or not
* @param {AST} node postcss ast node
* @param {Set} selectors selectors used in content files
*/
/**
* Extract the selectors present in the passed string using a purgecss extractor
* @param {array} content Array of content
* @param {array} extractors Array of extractors
*/
}, {
key: "evaluateRule",
value: function evaluateRule(node, selectors) {
var _this2 = this;
}, {
key: 'extractRawSelector',
value: function extractRawSelector(content, extractors) {
var selectors = new Set();
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
var annotation = node.prev();
if (this.isIgnoreAnnotation(annotation, 'next') || this.ignore === true) return;
var keepSelector = true;
node.selector = selectorParser(function (selectorsParsed) {
selectorsParsed.walk(function (selector) {
var selectorsInRule = [];
try {
for (var _iterator4 = content[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var _ref2 = _step4.value;
var raw = _ref2.raw;
var extension = _ref2.extension;
var extractor = this.getFileExtractor('.' + extension, extractors);
selectors = new Set([].concat(toConsumableArray(selectors), toConsumableArray(this.extractSelectors(raw, extractor))));
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
if (selector.type === 'selector') {
// if inside :not pseudo class, ignore
if (selector.parent && selector.parent.value === ':not' && selector.parent.type === 'pseudo') {
return;
}
return selectors;
}
var _iteratorNormalCompletion7 = true;
var _didIteratorError7 = false;
var _iteratorError7 = undefined;
/**
* Extract the selectors present in the files using a purgecss extractor
* @param {array} files Array of files path or glob pattern
* @param {array} extractors Array of extractors
*/
}, {
key: 'extractFileSelector',
value: function extractFileSelector(files, extractors) {
var selectors = new Set();
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
try {
for (var _iterator5 = files[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var globfile = _step5.value;
for (var _iterator7 = selector.nodes[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
var _step7$value = _step7.value,
type = _step7$value.type,
value = _step7$value.value;
var filesnames = [];
if (fs.existsSync(globfile)) {
filesnames.push(globfile);
} else {
filesnames = glob.sync(globfile);
}
var _iteratorNormalCompletion6 = true;
var _didIteratorError6 = false;
var _iteratorError6 = undefined;
try {
for (var _iterator6 = filesnames[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
var file = _step6.value;
var content = fs.readFileSync(file, 'utf8');
var extractor = this.getFileExtractor(file, extractors);
selectors = new Set([].concat(toConsumableArray(selectors), toConsumableArray(this.extractSelectors(content, extractor))));
}
} catch (err) {
_didIteratorError6 = true;
_iteratorError6 = err;
} finally {
try {
if (!_iteratorNormalCompletion6 && _iterator6.return) {
_iterator6.return();
}
} finally {
if (_didIteratorError6) {
throw _iteratorError6;
}
}
}
if (SELECTOR_STANDARD_TYPES.includes(type) && typeof value !== 'undefined' && /^\d/g.test(value) === false) {
selectorsInRule.push(value);
} else if (type === 'tag' && !/[+]|n|-|(even)|(odd)|^from$|^to$|^\d/.test(value)) {
// test if we do not have a pseudo class parameter (e.g. 2n in :nth-child(2n))
selectorsInRule.push(value);
}
}
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
_didIteratorError7 = true;
_iteratorError7 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return) {
_iterator5.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
}
try {
if (!_iteratorNormalCompletion7 && _iterator7.return != null) {
_iterator7.return();
}
} finally {
if (_didIteratorError7) {
throw _iteratorError7;
}
}
}
return selectors;
}
keepSelector = _this2.shouldKeepSelector(selectors, selectorsInRule);
/**
* Get the extractor corresponding to the extension file
* @param {string} filename Name of the file
* @param {array} extractors Array of extractors definition objects
*/
}, {
key: 'getFileExtractor',
value: function getFileExtractor(filename) {
var extractors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
if (!extractors.length) return DefaultExtractor;
var extractorObj = extractors.find(function (extractor) {
return extractor.extensions.find(function (ext) {
return filename.endsWith(ext);
});
});
return extractorObj.extractor;
}
/**
* Use the extract function of the extractor to get the list of selectors
* @param {string} content Content (e.g: html file)
* @param {object} extractor Purgecss extractor use to extract the selector
*/
}, {
key: 'extractSelectors',
value: function extractSelectors(content, extractor) {
var selectors = new Set();
var arraySelector = extractor.extract(content);
if (arraySelector === null) {
throw new Error(ERROR_EXTRACTER_FAILED);
if (!keepSelector) {
if (_this2.options.rejected) _this2.selectorsRemoved.add(selector.toString());
selector.remove();
}
arraySelector.forEach(function (selector) {
selectors.add(selector);
});
// Remove empty string
selectors.delete('');
return selectors;
}
}
});
}).processSync(node.selector); // loop declarations
/**
* Use postcss to walk through the css ast and remove unused css
* @param {*} selectors selectors used in content files
*/
if (keepSelector) {
var _iteratorNormalCompletion8 = true;
var _didIteratorError8 = false;
var _iteratorError8 = undefined;
}, {
key: 'getSelectorsCss',
value: function getSelectorsCss(selectors) {
var _this = this;
try {
for (var _iterator8 = node.nodes[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
var _step8$value = _step8.value,
prop = _step8$value.prop,
value = _step8$value.value;
this.root.walk(function (node) {
if (node.type === 'rule') {
return _this.evaluateRule(node, selectors);
}
if (node.type === 'atrule') {
return _this.evaluateAtRule(node);
}
if (node.type === 'comment') {
if (_this.isIgnoreAnnotation(node, 'start')) _this.ignore = true;else if (_this.isIgnoreAnnotation(node, 'end')) _this.ignore = false;
}
});
}
if (this.options.keyframes) {
if (prop === 'animation' || prop === 'animation-name') {
var _iteratorNormalCompletion9 = true;
var _didIteratorError9 = false;
var _iteratorError9 = undefined;
/**
* Evaluate css selector and decide if it should be removed or not
* @param {AST} node postcss ast node
* @param {Set} selectors selectors used in content files
*/
}, {
key: 'evaluateRule',
value: function evaluateRule(node, selectors) {
var _this2 = this;
var annotation = node.prev();
if (this.isIgnoreAnnotation(annotation, 'next') || this.ignore === true) return;
var keepSelector = true;
node.selector = selectorParser(function (selectorsParsed) {
selectorsParsed.walk(function (selector) {
var selectorsInRule = [];
if (selector.type === 'selector') {
// if inside :not pseudo class, ignore
if (selector.parent && selector.parent.value === ':not' && selector.parent.type === 'pseudo') {
return;
}
var _iteratorNormalCompletion7 = true;
var _didIteratorError7 = false;
var _iteratorError7 = undefined;
try {
for (var _iterator7 = selector.nodes[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
var _ref3 = _step7.value;
var type = _ref3.type;
var value = _ref3.value;
if (SELECTOR_STANDARD_TYPES.includes(type) && typeof value !== 'undefined' && /^\d/g.test(value) === false) {
selectorsInRule.push(value);
} else if (type === 'tag' && !/[+]|n|-|(even)|(odd)|^from$|^to$|^\d/.test(value)) {
// test if we do not have a pseudo class parameter (e.g. 2n in :nth-child(2n))
selectorsInRule.push(value);
}
}
} catch (err) {
_didIteratorError7 = true;
_iteratorError7 = err;
} finally {
try {
if (!_iteratorNormalCompletion7 && _iterator7.return) {
_iterator7.return();
}
} finally {
if (_didIteratorError7) {
throw _iteratorError7;
}
}
}
keepSelector = _this2.shouldKeepSelector(selectors, selectorsInRule);
if (!keepSelector) {
if (_this2.options.rejected) _this2.selectorsRemoved.add(selector.toString());
selector.remove();
}
}
});
}).processSync(node.selector);
// loop declarations
if (keepSelector) {
var _iteratorNormalCompletion8 = true;
var _didIteratorError8 = false;
var _iteratorError8 = undefined;
try {
for (var _iterator8 = node.nodes[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
var _ref4 = _step8.value;
var prop = _ref4.prop;
var value = _ref4.value;
if (this.options.keyframes) {
if (prop === 'animation' || prop === 'animation-name') {
var _iteratorNormalCompletion9 = true;
var _didIteratorError9 = false;
var _iteratorError9 = undefined;
try {
for (var _iterator9 = value.split(' ')[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
var word = _step9.value;
this.usedAnimations.add(word);
}
} catch (err) {
_didIteratorError9 = true;
_iteratorError9 = err;
} finally {
try {
if (!_iteratorNormalCompletion9 && _iterator9.return) {
_iterator9.return();
}
} finally {
if (_didIteratorError9) {
throw _iteratorError9;
}
}
}
}
}
if (this.options.fontFace) {
if (prop === 'font-family') {
this.usedFontFaces.add(value);
}
}
}
for (var _iterator9 = value.split(/[\s,]+/)[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
var word = _step9.value;
this.usedAnimations.add(word);
}
} catch (err) {
_didIteratorError8 = true;
_iteratorError8 = err;
_didIteratorError9 = true;
_iteratorError9 = err;
} finally {
try {
if (!_iteratorNormalCompletion8 && _iterator8.return) {
_iterator8.return();
}
} finally {
if (_didIteratorError8) {
throw _iteratorError8;
}
try {
if (!_iteratorNormalCompletion9 && _iterator9.return != null) {
_iterator9.return();
}
} finally {
if (_didIteratorError9) {
throw _iteratorError9;
}
}
}
}
}
var parent = node.parent;
// Remove empty rules
if (!node.selector) node.remove();
if (this.isRuleEmpty(parent)) parent.remove();
if (this.options.fontFace) {
if (prop === 'font-family') {
this.usedFontFaces.add(value);
}
}
}
} catch (err) {
_didIteratorError8 = true;
_iteratorError8 = err;
} finally {
try {
if (!_iteratorNormalCompletion8 && _iterator8.return != null) {
_iterator8.return();
}
} finally {
if (_didIteratorError8) {
throw _iteratorError8;
}
}
}
}
/**
* Evaluate at-rule and register it for future reference
* @param {AST} node postcss ast node
*/
var parent = node.parent; // Remove empty rules
}, {
key: 'evaluateAtRule',
value: function evaluateAtRule(node) {
if (this.options.keyframes && node.name.endsWith('keyframes')) {
this.atRules.keyframes.push(node);
return;
}
if (!node.selector) node.remove();
if (this.isRuleEmpty(parent)) parent.remove();
}
/**
* Evaluate at-rule and register it for future reference
* @param {AST} node postcss ast node
*/
if (this.options.fontFace && node.name === 'font-face') {
var _iteratorNormalCompletion10 = true;
var _didIteratorError10 = false;
var _iteratorError10 = undefined;
}, {
key: "evaluateAtRule",
value: function evaluateAtRule(node) {
if (this.options.keyframes && node.name.endsWith('keyframes')) {
this.atRules.keyframes.push(node);
return;
}
try {
for (var _iterator10 = node.nodes[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
var _ref5 = _step10.value;
var prop = _ref5.prop;
var value = _ref5.value;
if (this.options.fontFace && node.name === 'font-face') {
var _iteratorNormalCompletion10 = true;
var _didIteratorError10 = false;
var _iteratorError10 = undefined;
if (prop === 'font-family') {
this.atRules.fontFace.push({
name: value,
node: node
});
}
}
} catch (err) {
_didIteratorError10 = true;
_iteratorError10 = err;
} finally {
try {
if (!_iteratorNormalCompletion10 && _iterator10.return) {
_iterator10.return();
}
} finally {
if (_didIteratorError10) {
throw _iteratorError10;
}
}
}
try {
for (var _iterator10 = node.nodes[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
var _step10$value = _step10.value,
prop = _step10$value.prop,
value = _step10$value.value;
return;
if (prop === 'font-family') {
this.atRules.fontFace.push({
name: value,
node: node
});
}
}
} catch (err) {
_didIteratorError10 = true;
_iteratorError10 = err;
} finally {
try {
if (!_iteratorNormalCompletion10 && _iterator10.return != null) {
_iterator10.return();
}
} finally {
if (_didIteratorError10) {
throw _iteratorError10;
}
}
}
/**
* Check if the node is a css comment to ignore the selector rule
* @param {object} node Node of postcss abstract syntax tree
* @param {string} type Type of css comment (next, start, end)
*/
return;
}
}
/**
* Check if the node is a css comment to ignore the selector rule
* @param {object} node Node of postcss abstract syntax tree
* @param {string} type Type of css comment (next, start, end)
*/
}, {
key: 'isIgnoreAnnotation',
value: function isIgnoreAnnotation(node, type) {
if (node && node.type === 'comment') {
switch (type) {
case 'next':
return node.text.includes(IGNORE_ANNOTATION_NEXT);
case 'start':
return node.text.includes(IGNORE_ANNOTATION_START);
case 'end':
return node.text.includes(IGNORE_ANNOTATION_END);
}
}
return false;
}
}, {
key: "isIgnoreAnnotation",
value: function isIgnoreAnnotation(node, type) {
if (node && node.type === 'comment') {
switch (type) {
case 'next':
return node.text.includes(IGNORE_ANNOTATION_NEXT);
/**
* Check if the node correspond to an empty css rule
* @param {object} node Node of postcss abstract syntax tree
*/
case 'start':
return node.text.includes(IGNORE_ANNOTATION_START);
}, {
key: 'isRuleEmpty',
value: function isRuleEmpty(node) {
if (node.type === 'decl' && !node.value || node.type === 'rule' && !node.selector || node.nodes && !node.nodes.length || node.type === 'atrule' && (!node.nodes && !node.params || !node.params && !node.nodes.length)) {
return true;
}
return false;
case 'end':
return node.text.includes(IGNORE_ANNOTATION_END);
}
}
/**
* Determine if the selector should be kept, based on the selectors found in the files
* @param {Set} selectorsInContent Set of css selectors found in the content files
* @param {Array} selectorsInRule Array of selectors
*/
return false;
}
/**
* Check if the node correspond to an empty css rule
* @param {object} node Node of postcss abstract syntax tree
*/
}, {
key: 'shouldKeepSelector',
value: function shouldKeepSelector(selectorsInContent, selectorsInRule) {
var _iteratorNormalCompletion11 = true;
var _didIteratorError11 = false;
var _iteratorError11 = undefined;
}, {
key: "isRuleEmpty",
value: function isRuleEmpty(node) {
if (node.type === 'decl' && !node.value || node.type === 'rule' && !node.selector || node.nodes && !node.nodes.length || node.type === 'atrule' && (!node.nodes && !node.params || !node.params && !node.nodes.length)) {
return true;
}
try {
for (var _iterator11 = selectorsInRule[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
var selector = _step11.value;
return false;
}
/**
* Determine if the selector should be kept, based on the selectors found in the files
* @param {Set} selectorsInContent Set of css selectors found in the content files
* @param {Array} selectorsInRule Array of selectors
*/
// pseudo class
var unescapedSelector = selector.replace(/\\/g, '');
}, {
key: "shouldKeepSelector",
value: function shouldKeepSelector(selectorsInContent, selectorsInRule) {
var _iteratorNormalCompletion11 = true;
var _didIteratorError11 = false;
var _iteratorError11 = undefined;
if (unescapedSelector.startsWith(':')) {
continue;
}
try {
for (var _iterator11 = selectorsInRule[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
var selector = _step11.value;
// pseudo class
var unescapedSelector = selector.replace(/\\/g, '');
// If the selector is whitelisted with children keep, simply
// returns true to keep all children selectors
if (this.isSelectorWhitelistedChildren(unescapedSelector)) {
return true;
}
if (unescapedSelector.startsWith(':')) {
continue;
} // If the selector is whitelisted with children keep, simply
// returns true to keep all children selectors
if (!(selectorsInContent.has(unescapedSelector) || CSS_WHITELIST.includes(unescapedSelector) || this.isSelectorWhitelisted(unescapedSelector))) {
return false;
}
}
} catch (err) {
_didIteratorError11 = true;
_iteratorError11 = err;
} finally {
try {
if (!_iteratorNormalCompletion11 && _iterator11.return) {
_iterator11.return();
}
} finally {
if (_didIteratorError11) {
throw _iteratorError11;
}
}
}
if (this.isSelectorWhitelistedChildren(unescapedSelector)) {
return true;
}
if (!(selectorsInContent.has(unescapedSelector) || CSS_WHITELIST.includes(unescapedSelector) || this.isSelectorWhitelisted(unescapedSelector))) {
return false;
}
}
} catch (err) {
_didIteratorError11 = true;
_iteratorError11 = err;
} finally {
try {
if (!_iteratorNormalCompletion11 && _iterator11.return != null) {
_iterator11.return();
}
} finally {
if (_didIteratorError11) {
throw _iteratorError11;
}
}
}
/**
* Check if the selector is whitelisted by the options whitelist or whitelistPatterns
* @param {string} selector css selector
*/
return true;
}
/**
* Check if the selector is whitelisted by the options whitelist or whitelistPatterns
* @param {string} selector css selector
*/
}, {
key: 'isSelectorWhitelisted',
value: function isSelectorWhitelisted(selector) {
return !!(CSS_WHITELIST.includes(selector) || this.options.whitelist && this.options.whitelist.some(function (v) {
return v === selector;
}) || this.options.whitelistPatterns && this.options.whitelistPatterns.some(function (v) {
return v.test(selector);
}));
}
}, {
key: "isSelectorWhitelisted",
value: function isSelectorWhitelisted(selector) {
return !!(CSS_WHITELIST.includes(selector) || this.options.whitelist && this.options.whitelist.some(function (v) {
return v === selector;
}) || this.options.whitelistPatterns && this.options.whitelistPatterns.some(function (v) {
return v.test(selector);
}));
}
/**
* Check if the selector is whitelisted by the whitelistPatternsChildren
* options element
*
* @param {string} selector
*/
/**
* Check if the selector is whitelisted by the whitelistPatternsChildren
* options element
*
* @param {string} selector
*/
}, {
key: "isSelectorWhitelistedChildren",
value: function isSelectorWhitelistedChildren(selector) {
return !!(this.options.whitelistPatternsChildren && this.options.whitelistPatternsChildren.some(function (v) {
return v.test(selector);
}));
}
}]);
}, {
key: 'isSelectorWhitelistedChildren',
value: function isSelectorWhitelistedChildren(selector) {
return !!(this.options.whitelistPatternsChildren && this.options.whitelistPatternsChildren.some(function (v) {
return v.test(selector);
}));
}
}]);
return Purgecss;
return Purgecss;
}();
export default Purgecss;

@@ -10,2 +10,73 @@ 'use strict';

function _typeof(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function (obj) {
return typeof obj;
};
} else {
_typeof = function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
}
}
function _iterableToArray(iter) {
if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance");
}
// Copyright Joyent, Inc. and other Node contributors.

@@ -31,3 +102,2 @@ //

// USE OR OTHER DEALINGS IN THE SOFTWARE.
// resolves . and .. elements in a path array with directory names there

@@ -40,4 +110,6 @@ // must be no slashes, empty elements, or device names (c:\) in the array

var up = 0;
for (var i = parts.length - 1; i >= 0; i--) {
var last = parts[i];
if (last === '.') {

@@ -52,5 +124,5 @@ parts.splice(i, 1);

}
}
} // if the path is allowed to go above the root, restore leading ..s
// if the path is allowed to go above the root, restore leading ..s
if (allowAboveRoot) {

@@ -63,13 +135,14 @@ for (; up--; up) {

return parts;
}
} // Split a filename into [root, dir, basename, ext], unix version
// 'root' is just a slash, or nothing.
// Split a filename into [root, dir, basename, ext], unix version
// 'root' is just a slash, or nothing.
var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
var splitPath = function splitPath(filename) {
var splitPath = function (filename) {
return splitPathRe.exec(filename).slice(1);
};
}; // path.resolve([from ...], to)
// posix version
// path.resolve([from ...], to)
// posix version
function resolve() {

@@ -80,5 +153,4 @@ var resolvedPath = '',

for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
var path = i >= 0 ? arguments[i] : '/';
var path = i >= 0 ? arguments[i] : '/'; // Skip empty and invalid entries
// Skip empty and invalid entries
if (typeof path !== 'string') {

@@ -92,21 +164,18 @@ throw new TypeError('Arguments to path.resolve must be strings');

resolvedAbsolute = path.charAt(0) === '/';
}
// At this point the path should be resolved to a full absolute path, but
} // At this point the path should be resolved to a full absolute path, but
// handle relative paths to be safe (might happen when process.cwd() fails)
// Normalize the path
// Normalize the path
resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function (p) {
return !!p;
}), !resolvedAbsolute).join('/');
return (resolvedAbsolute ? '/' : '') + resolvedPath || '.';
}
// path.normalize(path)
// posix version
function normalize(path) {
var isPathAbsolute = isAbsolute(path),
trailingSlash = substr(path, -1) === '/';
trailingSlash = substr(path, -1) === '/'; // Normalize the path
// Normalize the path
path = normalizeArray(filter(path.split('/'), function (p) {

@@ -119,2 +188,3 @@ return !!p;

}
if (path && trailingSlash) {

@@ -126,8 +196,7 @@ path += '/';

}
// posix version
function isAbsolute(path) {
return path.charAt(0) === '/';
}
} // posix version
// posix version
function join() {

@@ -139,8 +208,8 @@ var paths = Array.prototype.slice.call(arguments, 0);

}
return p;
}).join('/'));
}
} // path.relative(from, to)
// posix version
// path.relative(from, to)
// posix version
function relative(from, to) {

@@ -152,2 +221,3 @@ from = resolve(from).substr(1);

var start = 0;
for (; start < arr.length; start++) {

@@ -158,2 +228,3 @@ if (arr[start] !== '') break;

var end = arr.length - 1;
for (; end >= 0; end--) {

@@ -169,5 +240,5 @@ if (arr[end] !== '') break;

var toParts = trim(to.split('/'));
var length = Math.min(fromParts.length, toParts.length);
var samePartsLength = length;
for (var i = 0; i < length; i++) {

@@ -181,2 +252,3 @@ if (fromParts[i] !== toParts[i]) {

var outputParts = [];
for (var i = samePartsLength; i < fromParts.length; i++) {

@@ -187,9 +259,6 @@ outputParts.push('..');

outputParts = outputParts.concat(toParts.slice(samePartsLength));
return outputParts.join('/');
}
var sep = '/';
var delimiter = ':';
function dirname(path) {

@@ -212,12 +281,11 @@ var result = splitPath(path),

}
function basename(path, ext) {
var f = splitPath(path)[2]; // TODO: make this comparison case-insensitive on windows?
function basename(path, ext) {
var f = splitPath(path)[2];
// TODO: make this comparison case-insensitive on windows?
if (ext && f.substr(-1 * ext.length) === ext) {
f = f.substr(0, f.length - ext.length);
}
return f;
}
function extname(path) {

@@ -238,12 +306,15 @@ return splitPath(path)[3];

};
function filter(xs, f) {
if (xs.filter) return xs.filter(f);
var res = [];
for (var i = 0; i < xs.length; i++) {
if (f(xs[i], i, xs)) res.push(xs[i]);
}
return res;
}
} // String.prototype.substr - negative index don't work in IE8
// String.prototype.substr - negative index don't work in IE8
var substr = 'ab'.substr(-1) === 'b' ? function (str, start, len) {

@@ -257,13 +328,12 @@ return str.substr(start, len);

//
var defaultOptions = {
css: [],
content: [],
extractors: [],
whitelist: [],
output: undefined,
stdout: false,
keyframes: false,
fontFace: false,
rejected: false
css: [],
content: [],
extractors: [],
whitelist: [],
output: undefined,
stdout: false,
keyframes: false,
fontFace: false,
rejected: false
};

@@ -274,5 +344,4 @@

var IGNORE_ANNOTATION_END = 'purgecss end ignore';
var CONFIG_FILENAME = 'purgecss.config.js';
var CONFIG_FILENAME = 'purgecss.config.js'; // Error Message
// Error Message
var ERROR_CONFIG_FILE_LOADING = 'Error loading the config file';

@@ -282,10 +351,7 @@ var ERROR_MISSING_CONTENT = 'No content provided.';

var ERROR_EXTRACTER_FAILED = 'The extractor has failed to extract the selectors.';
var ERROR_OPTIONS_TYPE = 'Error Type Options: expected an object';
var ERROR_OUTPUT_TYPE = 'Error Type option output: expected a string';
var ERROR_EXTRACTERS_TYPE = 'Error Type option extractors: expected an array';
var ERROR_WHITELIST_TYPE = 'Error Type option whitelist: expected an array';
var ERROR_WHITELIST_PATTERNS_TYPE = 'Error Type option whitelistPatterns: expected an array';
var ERROR_STDOUT_TYPE = 'Error Type option stdout: expected a boolean';

@@ -297,778 +363,721 @@

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
return typeof obj;
} : function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
var classCallCheck = function (instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
var DefaultExtractor =
/*#__PURE__*/
function () {
function DefaultExtractor() {
_classCallCheck(this, DefaultExtractor);
}
};
var createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
_createClass(DefaultExtractor, null, [{
key: "extract",
value: function extract(content) {
return content.match(/[A-Za-z0-9_-]+/g) || [];
}
}
}]);
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
return DefaultExtractor;
}();
var toConsumableArray = function (arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
var Purgecss =
/*#__PURE__*/
function () {
function Purgecss(options) {
_classCallCheck(this, Purgecss);
return arr2;
} else {
return Array.from(arr);
_defineProperty(this, "atRules", {
keyframes: [],
fontFace: []
});
_defineProperty(this, "usedAnimations", new Set());
_defineProperty(this, "usedFontFaces", new Set());
_defineProperty(this, "selectorsRemoved", new Set());
_defineProperty(this, "ignore", false);
if (typeof options === 'string' || typeof options === 'undefined') options = this.loadConfigFile(options);
this.checkOptions(options);
this.options = Object.assign(defaultOptions, options);
}
};
/**
* Load the configuration file from the path
* @param {string} configFile Path of the config file
*/
var DefaultExtractor = function () {
function DefaultExtractor() {
classCallCheck(this, DefaultExtractor);
}
createClass(DefaultExtractor, null, [{
key: "extract",
value: function extract(content) {
return content.match(/[A-Za-z0-9_-]+/g) || [];
}
}]);
return DefaultExtractor;
}();
_createClass(Purgecss, [{
key: "loadConfigFile",
value: function loadConfigFile(configFile) {
var pathConfig = typeof configFile === 'undefined' ? CONFIG_FILENAME : configFile;
var options;
//
try {
var t = path.resolve(process.cwd(), pathConfig);
options = require(t);
} catch (e) {
throw new Error(ERROR_CONFIG_FILE_LOADING + e.message);
}
var Purgecss = function () {
function Purgecss(options) {
classCallCheck(this, Purgecss);
this.atRules = {
keyframes: [],
fontFace: []
};
this.usedAnimations = new Set();
this.usedFontFaces = new Set();
this.selectorsRemoved = new Set();
this.ignore = false;
return options;
}
/**
* Verify that the purgecss options provided are valid
* @param {object} options Purgecss options
*/
if (typeof options === 'string' || typeof options === 'undefined') options = this.loadConfigFile(options);
this.checkOptions(options);
this.options = Object.assign(defaultOptions, options);
}, {
key: "checkOptions",
value: function checkOptions(options) {
if (_typeof(options) !== 'object') throw new TypeError(ERROR_OPTIONS_TYPE);
if (!options.content || !options.content.length) throw new Error(ERROR_MISSING_CONTENT);
if (!options.css || !options.css.length) throw new Error(ERROR_MISSING_CSS);
if (options.output && typeof options.output !== 'string') throw new TypeError(ERROR_OUTPUT_TYPE);
if (options.extractors && !Array.isArray(options.extractors)) throw new TypeError(ERROR_EXTRACTERS_TYPE);
if (options.whitelist && !Array.isArray(options.whitelist)) throw new TypeError(ERROR_WHITELIST_TYPE);
if (options.stdout && typeof options.stdout !== 'boolean') throw new TypeError(ERROR_STDOUT_TYPE);
if (options.whitelistPatterns && !Array.isArray(options.whitelistPatterns)) throw new TypeError(ERROR_WHITELIST_PATTERNS_TYPE);
}
/**
* Main function that purge the css file
*/
}, {
key: "purge",
value: function purge() {
// Get selectors from content files
var _this$options = this.options,
content = _this$options.content,
extractors = _this$options.extractors,
css = _this$options.css;
var fileFormatContents = content.filter(function (o) {
return typeof o === 'string';
});
var rawFormatContents = content.filter(function (o) {
return _typeof(o) === 'object';
});
var cssFileSelectors = this.extractFileSelector(fileFormatContents, extractors);
var cssRawSelectors = this.extractRawSelector(rawFormatContents, extractors); // Get css selectors and remove unused ones
return this.getCssContents(css, new Set([].concat(_toConsumableArray(cssFileSelectors), _toConsumableArray(cssRawSelectors))));
}
/**
* Load the configuration file from the path
* @param {string} configFile Path of the config file
* Get the content of the css files, or return the raw content
* @param {array} cssOptions Array of css options, files and raw
* @param {Set} cssSelectors Set of all extracted css selectors
*/
}, {
key: "getCssContents",
value: function getCssContents(cssOptions, cssSelectors) {
var sources = []; // resolve any globs and flatten again
createClass(Purgecss, [{
key: 'loadConfigFile',
value: function loadConfigFile(configFile) {
var pathConfig = typeof configFile === 'undefined' ? CONFIG_FILENAME : configFile;
var options = void 0;
try {
var t = path.resolve(process.cwd(), pathConfig);
options = require(t);
} catch (e) {
throw new Error(ERROR_CONFIG_FILE_LOADING + e.message);
}
return options;
}
cssOptions = cssOptions.map(function (option) {
return typeof option === 'string' ? glob.sync(option) : option;
});
cssOptions = [].concat.apply([], cssOptions);
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
/**
* Verify that the purgecss options provided are valid
* @param {object} options Purgecss options
*/
try {
for (var _iterator = cssOptions[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var option = _step.value;
var file = null;
var rejected = null;
var cssContent = '';
}, {
key: 'checkOptions',
value: function checkOptions(options) {
if ((typeof options === 'undefined' ? 'undefined' : _typeof(options)) !== 'object') throw new TypeError(ERROR_OPTIONS_TYPE);
if (!options.content || !options.content.length) throw new Error(ERROR_MISSING_CONTENT);
if (!options.css || !options.css.length) throw new Error(ERROR_MISSING_CSS);
if (options.output && typeof options.output !== 'string') throw new TypeError(ERROR_OUTPUT_TYPE);
if (options.extractors && !Array.isArray(options.extractors)) throw new TypeError(ERROR_EXTRACTERS_TYPE);
if (options.whitelist && !Array.isArray(options.whitelist)) throw new TypeError(ERROR_WHITELIST_TYPE);
if (options.stdout && typeof options.stdout !== 'boolean') throw new TypeError(ERROR_STDOUT_TYPE);
if (options.whitelistPatterns && !Array.isArray(options.whitelistPatterns)) throw new TypeError(ERROR_WHITELIST_PATTERNS_TYPE);
}
if (typeof option === 'string') {
file = option;
cssContent = this.options.stdin ? file : fs.readFileSync(file, 'utf8');
} else {
cssContent = option.raw;
}
/**
* Main function that purge the css file
*/
this.root = postcss.parse(cssContent); // purge selectors
}, {
key: 'purge',
value: function purge() {
// Get selectors from content files
var _options = this.options,
content = _options.content,
extractors = _options.extractors,
css = _options.css;
this.getSelectorsCss(cssSelectors); // purge keyframes
if (this.options.keyframes) this.removeUnusedKeyframes(); // purge font face
var fileFormatContents = content.filter(function (o) {
return typeof o === 'string';
});
var rawFormatContents = content.filter(function (o) {
return (typeof o === 'undefined' ? 'undefined' : _typeof(o)) === 'object';
});
if (this.options.fontFace) this.removeUnusedFontFaces();
var purgeResult = {
file: file,
css: this.root.toString(),
rejected: rejected
};
var cssFileSelectors = this.extractFileSelector(fileFormatContents, extractors);
var cssRawSelectors = this.extractRawSelector(rawFormatContents, extractors);
if (this.options.rejected) {
rejected = Array.from(this.selectorsRemoved);
this.selectorsRemoved.clear();
}
// Get css selectors and remove unused ones
return this.getCssContents(css, new Set([].concat(toConsumableArray(cssFileSelectors), toConsumableArray(cssRawSelectors))));
purgeResult.rejected = rejected;
sources.push(purgeResult);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
/**
* Get the content of the css files, or return the raw content
* @param {array} cssOptions Array of css options, files and raw
* @param {Set} cssSelectors Set of all extracted css selectors
*/
return sources;
}
/**
* Remove Keyframes that were never used
*/
}, {
key: 'getCssContents',
value: function getCssContents(cssOptions, cssSelectors) {
var sources = [];
}, {
key: "removeUnusedKeyframes",
value: function removeUnusedKeyframes() {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
// resolve any globs and flatten again
cssOptions = cssOptions.map(function (option) {
return typeof option === 'string' ? glob.sync(option) : option;
});
cssOptions = [].concat.apply([], cssOptions);
try {
for (var _iterator2 = this.atRules.keyframes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var node = _step2.value;
var nodeName = node.params;
var used = this.usedAnimations.has(nodeName);
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
if (!used) {
node.remove();
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
/**
* Remove Font-Faces that were never used
*/
try {
for (var _iterator = cssOptions[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var option = _step.value;
}, {
key: "removeUnusedFontFaces",
value: function removeUnusedFontFaces() {
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
var file = null;
var rejected = null;
var cssContent = '';
if (typeof option === 'string') {
file = option;
cssContent = this.options.stdin ? file : fs.readFileSync(file, 'utf8');
} else {
cssContent = option.raw;
}
try {
for (var _iterator3 = this.atRules.fontFace[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var _step3$value = _step3.value,
node = _step3$value.node,
name = _step3$value.name;
var used = this.usedFontFaces.has(name);
this.root = postcss.parse(cssContent);
if (!used) {
node.remove();
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
}
/**
* Extract the selectors present in the passed string using a purgecss extractor
* @param {array} content Array of content
* @param {array} extractors Array of extractors
*/
// purge selectors
this.getSelectorsCss(cssSelectors);
}, {
key: "extractRawSelector",
value: function extractRawSelector(content, extractors) {
var selectors = new Set();
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
// purge keyframes
if (this.options.keyframes) this.removeUnusedKeyframes();
try {
for (var _iterator4 = content[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var _step4$value = _step4.value,
raw = _step4$value.raw,
extension = _step4$value.extension;
var extractor = this.getFileExtractor(".".concat(extension), extractors);
selectors = new Set([].concat(_toConsumableArray(selectors), _toConsumableArray(this.extractSelectors(raw, extractor))));
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return != null) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
// purge font face
if (this.options.fontFace) this.removeUnusedFontFaces();
return selectors;
}
/**
* Extract the selectors present in the files using a purgecss extractor
* @param {array} files Array of files path or glob pattern
* @param {array} extractors Array of extractors
*/
var purgeResult = {
file: file,
css: this.root.toString(),
rejected: rejected
};
}, {
key: "extractFileSelector",
value: function extractFileSelector(files, extractors) {
var selectors = new Set();
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
if (this.options.rejected) {
rejected = Array.from(this.selectorsRemoved);
this.selectorsRemoved.clear();
}
try {
for (var _iterator5 = files[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var globfile = _step5.value;
var filesnames = [];
purgeResult.rejected = rejected;
if (fs.existsSync(globfile)) {
filesnames.push(globfile);
} else {
filesnames = glob.sync(globfile);
}
sources.push(purgeResult);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
var _iteratorNormalCompletion6 = true;
var _didIteratorError6 = false;
var _iteratorError6 = undefined;
try {
for (var _iterator6 = filesnames[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
var file = _step6.value;
var content = fs.readFileSync(file, 'utf8');
var extractor = this.getFileExtractor(file, extractors);
selectors = new Set([].concat(_toConsumableArray(selectors), _toConsumableArray(this.extractSelectors(content, extractor))));
}
} catch (err) {
_didIteratorError6 = true;
_iteratorError6 = err;
} finally {
try {
if (!_iteratorNormalCompletion6 && _iterator6.return != null) {
_iterator6.return();
}
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
if (_didIteratorError6) {
throw _iteratorError6;
}
}
return sources;
}
}
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return != null) {
_iterator5.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
}
}
}
/**
* Remove Keyframes that were never used
*/
return selectors;
}
/**
* Get the extractor corresponding to the extension file
* @param {string} filename Name of the file
* @param {array} extractors Array of extractors definition objects
*/
}, {
key: 'removeUnusedKeyframes',
value: function removeUnusedKeyframes() {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
}, {
key: "getFileExtractor",
value: function getFileExtractor(filename) {
var extractors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
if (!extractors.length) return DefaultExtractor;
var extractorObj = extractors.find(function (extractor) {
return extractor.extensions.find(function (ext) {
return filename.endsWith(ext);
});
}) || DefaultExtractor;
return extractorObj.extractor;
}
/**
* Use the extract function of the extractor to get the list of selectors
* @param {string} content Content (e.g: html file)
* @param {object} extractor Purgecss extractor use to extract the selector
*/
try {
for (var _iterator2 = this.atRules.keyframes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var node = _step2.value;
}, {
key: "extractSelectors",
value: function extractSelectors(content, extractor) {
var selectors = new Set();
var arraySelector = typeof extractor.extract === 'undefined' ? extractor(content) : extractor.extract(content);
var nodeName = node.params;
var used = this.usedAnimations.has(nodeName);
if (arraySelector === null) {
throw new Error(ERROR_EXTRACTER_FAILED);
}
if (!used) {
node.remove();
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
arraySelector.forEach(function (selector) {
selectors.add(selector);
}); // Remove empty string
/**
* Remove Font-Faces that were never used
*/
selectors.delete('');
return selectors;
}
/**
* Use postcss to walk through the css ast and remove unused css
* @param {*} selectors selectors used in content files
*/
}, {
key: 'removeUnusedFontFaces',
value: function removeUnusedFontFaces() {
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
}, {
key: "getSelectorsCss",
value: function getSelectorsCss(selectors) {
var _this = this;
try {
for (var _iterator3 = this.atRules.fontFace[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var _ref = _step3.value;
var node = _ref.node;
var name = _ref.name;
this.root.walk(function (node) {
if (node.type === 'rule') {
return _this.evaluateRule(node, selectors);
}
var used = this.usedFontFaces.has(name);
if (node.type === 'atrule') {
return _this.evaluateAtRule(node);
}
if (!used) {
node.remove();
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
if (node.type === 'comment') {
if (_this.isIgnoreAnnotation(node, 'start')) _this.ignore = true;else if (_this.isIgnoreAnnotation(node, 'end')) _this.ignore = false;
}
});
}
/**
* Evaluate css selector and decide if it should be removed or not
* @param {AST} node postcss ast node
* @param {Set} selectors selectors used in content files
*/
/**
* Extract the selectors present in the passed string using a purgecss extractor
* @param {array} content Array of content
* @param {array} extractors Array of extractors
*/
}, {
key: "evaluateRule",
value: function evaluateRule(node, selectors) {
var _this2 = this;
}, {
key: 'extractRawSelector',
value: function extractRawSelector(content, extractors) {
var selectors = new Set();
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
var annotation = node.prev();
if (this.isIgnoreAnnotation(annotation, 'next') || this.ignore === true) return;
var keepSelector = true;
node.selector = selectorParser(function (selectorsParsed) {
selectorsParsed.walk(function (selector) {
var selectorsInRule = [];
try {
for (var _iterator4 = content[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var _ref2 = _step4.value;
var raw = _ref2.raw;
var extension = _ref2.extension;
var extractor = this.getFileExtractor('.' + extension, extractors);
selectors = new Set([].concat(toConsumableArray(selectors), toConsumableArray(this.extractSelectors(raw, extractor))));
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
if (selector.type === 'selector') {
// if inside :not pseudo class, ignore
if (selector.parent && selector.parent.value === ':not' && selector.parent.type === 'pseudo') {
return;
}
return selectors;
}
var _iteratorNormalCompletion7 = true;
var _didIteratorError7 = false;
var _iteratorError7 = undefined;
/**
* Extract the selectors present in the files using a purgecss extractor
* @param {array} files Array of files path or glob pattern
* @param {array} extractors Array of extractors
*/
}, {
key: 'extractFileSelector',
value: function extractFileSelector(files, extractors) {
var selectors = new Set();
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
try {
for (var _iterator5 = files[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var globfile = _step5.value;
for (var _iterator7 = selector.nodes[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
var _step7$value = _step7.value,
type = _step7$value.type,
value = _step7$value.value;
var filesnames = [];
if (fs.existsSync(globfile)) {
filesnames.push(globfile);
} else {
filesnames = glob.sync(globfile);
}
var _iteratorNormalCompletion6 = true;
var _didIteratorError6 = false;
var _iteratorError6 = undefined;
try {
for (var _iterator6 = filesnames[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
var file = _step6.value;
var content = fs.readFileSync(file, 'utf8');
var extractor = this.getFileExtractor(file, extractors);
selectors = new Set([].concat(toConsumableArray(selectors), toConsumableArray(this.extractSelectors(content, extractor))));
}
} catch (err) {
_didIteratorError6 = true;
_iteratorError6 = err;
} finally {
try {
if (!_iteratorNormalCompletion6 && _iterator6.return) {
_iterator6.return();
}
} finally {
if (_didIteratorError6) {
throw _iteratorError6;
}
}
}
if (SELECTOR_STANDARD_TYPES.includes(type) && typeof value !== 'undefined' && /^\d/g.test(value) === false) {
selectorsInRule.push(value);
} else if (type === 'tag' && !/[+]|n|-|(even)|(odd)|^from$|^to$|^\d/.test(value)) {
// test if we do not have a pseudo class parameter (e.g. 2n in :nth-child(2n))
selectorsInRule.push(value);
}
}
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
_didIteratorError7 = true;
_iteratorError7 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return) {
_iterator5.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
}
try {
if (!_iteratorNormalCompletion7 && _iterator7.return != null) {
_iterator7.return();
}
} finally {
if (_didIteratorError7) {
throw _iteratorError7;
}
}
}
return selectors;
}
keepSelector = _this2.shouldKeepSelector(selectors, selectorsInRule);
/**
* Get the extractor corresponding to the extension file
* @param {string} filename Name of the file
* @param {array} extractors Array of extractors definition objects
*/
}, {
key: 'getFileExtractor',
value: function getFileExtractor(filename) {
var extractors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
if (!extractors.length) return DefaultExtractor;
var extractorObj = extractors.find(function (extractor) {
return extractor.extensions.find(function (ext) {
return filename.endsWith(ext);
});
});
return extractorObj.extractor;
}
/**
* Use the extract function of the extractor to get the list of selectors
* @param {string} content Content (e.g: html file)
* @param {object} extractor Purgecss extractor use to extract the selector
*/
}, {
key: 'extractSelectors',
value: function extractSelectors(content, extractor) {
var selectors = new Set();
var arraySelector = extractor.extract(content);
if (arraySelector === null) {
throw new Error(ERROR_EXTRACTER_FAILED);
if (!keepSelector) {
if (_this2.options.rejected) _this2.selectorsRemoved.add(selector.toString());
selector.remove();
}
arraySelector.forEach(function (selector) {
selectors.add(selector);
});
// Remove empty string
selectors.delete('');
return selectors;
}
}
});
}).processSync(node.selector); // loop declarations
/**
* Use postcss to walk through the css ast and remove unused css
* @param {*} selectors selectors used in content files
*/
if (keepSelector) {
var _iteratorNormalCompletion8 = true;
var _didIteratorError8 = false;
var _iteratorError8 = undefined;
}, {
key: 'getSelectorsCss',
value: function getSelectorsCss(selectors) {
var _this = this;
try {
for (var _iterator8 = node.nodes[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
var _step8$value = _step8.value,
prop = _step8$value.prop,
value = _step8$value.value;
this.root.walk(function (node) {
if (node.type === 'rule') {
return _this.evaluateRule(node, selectors);
}
if (node.type === 'atrule') {
return _this.evaluateAtRule(node);
}
if (node.type === 'comment') {
if (_this.isIgnoreAnnotation(node, 'start')) _this.ignore = true;else if (_this.isIgnoreAnnotation(node, 'end')) _this.ignore = false;
}
});
}
if (this.options.keyframes) {
if (prop === 'animation' || prop === 'animation-name') {
var _iteratorNormalCompletion9 = true;
var _didIteratorError9 = false;
var _iteratorError9 = undefined;
/**
* Evaluate css selector and decide if it should be removed or not
* @param {AST} node postcss ast node
* @param {Set} selectors selectors used in content files
*/
}, {
key: 'evaluateRule',
value: function evaluateRule(node, selectors) {
var _this2 = this;
var annotation = node.prev();
if (this.isIgnoreAnnotation(annotation, 'next') || this.ignore === true) return;
var keepSelector = true;
node.selector = selectorParser(function (selectorsParsed) {
selectorsParsed.walk(function (selector) {
var selectorsInRule = [];
if (selector.type === 'selector') {
// if inside :not pseudo class, ignore
if (selector.parent && selector.parent.value === ':not' && selector.parent.type === 'pseudo') {
return;
}
var _iteratorNormalCompletion7 = true;
var _didIteratorError7 = false;
var _iteratorError7 = undefined;
try {
for (var _iterator7 = selector.nodes[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
var _ref3 = _step7.value;
var type = _ref3.type;
var value = _ref3.value;
if (SELECTOR_STANDARD_TYPES.includes(type) && typeof value !== 'undefined' && /^\d/g.test(value) === false) {
selectorsInRule.push(value);
} else if (type === 'tag' && !/[+]|n|-|(even)|(odd)|^from$|^to$|^\d/.test(value)) {
// test if we do not have a pseudo class parameter (e.g. 2n in :nth-child(2n))
selectorsInRule.push(value);
}
}
} catch (err) {
_didIteratorError7 = true;
_iteratorError7 = err;
} finally {
try {
if (!_iteratorNormalCompletion7 && _iterator7.return) {
_iterator7.return();
}
} finally {
if (_didIteratorError7) {
throw _iteratorError7;
}
}
}
keepSelector = _this2.shouldKeepSelector(selectors, selectorsInRule);
if (!keepSelector) {
if (_this2.options.rejected) _this2.selectorsRemoved.add(selector.toString());
selector.remove();
}
}
});
}).processSync(node.selector);
// loop declarations
if (keepSelector) {
var _iteratorNormalCompletion8 = true;
var _didIteratorError8 = false;
var _iteratorError8 = undefined;
try {
for (var _iterator8 = node.nodes[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
var _ref4 = _step8.value;
var prop = _ref4.prop;
var value = _ref4.value;
if (this.options.keyframes) {
if (prop === 'animation' || prop === 'animation-name') {
var _iteratorNormalCompletion9 = true;
var _didIteratorError9 = false;
var _iteratorError9 = undefined;
try {
for (var _iterator9 = value.split(' ')[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
var word = _step9.value;
this.usedAnimations.add(word);
}
} catch (err) {
_didIteratorError9 = true;
_iteratorError9 = err;
} finally {
try {
if (!_iteratorNormalCompletion9 && _iterator9.return) {
_iterator9.return();
}
} finally {
if (_didIteratorError9) {
throw _iteratorError9;
}
}
}
}
}
if (this.options.fontFace) {
if (prop === 'font-family') {
this.usedFontFaces.add(value);
}
}
}
for (var _iterator9 = value.split(/[\s,]+/)[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
var word = _step9.value;
this.usedAnimations.add(word);
}
} catch (err) {
_didIteratorError8 = true;
_iteratorError8 = err;
_didIteratorError9 = true;
_iteratorError9 = err;
} finally {
try {
if (!_iteratorNormalCompletion8 && _iterator8.return) {
_iterator8.return();
}
} finally {
if (_didIteratorError8) {
throw _iteratorError8;
}
try {
if (!_iteratorNormalCompletion9 && _iterator9.return != null) {
_iterator9.return();
}
} finally {
if (_didIteratorError9) {
throw _iteratorError9;
}
}
}
}
}
var parent = node.parent;
// Remove empty rules
if (!node.selector) node.remove();
if (this.isRuleEmpty(parent)) parent.remove();
if (this.options.fontFace) {
if (prop === 'font-family') {
this.usedFontFaces.add(value);
}
}
}
} catch (err) {
_didIteratorError8 = true;
_iteratorError8 = err;
} finally {
try {
if (!_iteratorNormalCompletion8 && _iterator8.return != null) {
_iterator8.return();
}
} finally {
if (_didIteratorError8) {
throw _iteratorError8;
}
}
}
}
/**
* Evaluate at-rule and register it for future reference
* @param {AST} node postcss ast node
*/
var parent = node.parent; // Remove empty rules
}, {
key: 'evaluateAtRule',
value: function evaluateAtRule(node) {
if (this.options.keyframes && node.name.endsWith('keyframes')) {
this.atRules.keyframes.push(node);
return;
}
if (!node.selector) node.remove();
if (this.isRuleEmpty(parent)) parent.remove();
}
/**
* Evaluate at-rule and register it for future reference
* @param {AST} node postcss ast node
*/
if (this.options.fontFace && node.name === 'font-face') {
var _iteratorNormalCompletion10 = true;
var _didIteratorError10 = false;
var _iteratorError10 = undefined;
}, {
key: "evaluateAtRule",
value: function evaluateAtRule(node) {
if (this.options.keyframes && node.name.endsWith('keyframes')) {
this.atRules.keyframes.push(node);
return;
}
try {
for (var _iterator10 = node.nodes[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
var _ref5 = _step10.value;
var prop = _ref5.prop;
var value = _ref5.value;
if (this.options.fontFace && node.name === 'font-face') {
var _iteratorNormalCompletion10 = true;
var _didIteratorError10 = false;
var _iteratorError10 = undefined;
if (prop === 'font-family') {
this.atRules.fontFace.push({
name: value,
node: node
});
}
}
} catch (err) {
_didIteratorError10 = true;
_iteratorError10 = err;
} finally {
try {
if (!_iteratorNormalCompletion10 && _iterator10.return) {
_iterator10.return();
}
} finally {
if (_didIteratorError10) {
throw _iteratorError10;
}
}
}
try {
for (var _iterator10 = node.nodes[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
var _step10$value = _step10.value,
prop = _step10$value.prop,
value = _step10$value.value;
return;
if (prop === 'font-family') {
this.atRules.fontFace.push({
name: value,
node: node
});
}
}
} catch (err) {
_didIteratorError10 = true;
_iteratorError10 = err;
} finally {
try {
if (!_iteratorNormalCompletion10 && _iterator10.return != null) {
_iterator10.return();
}
} finally {
if (_didIteratorError10) {
throw _iteratorError10;
}
}
}
/**
* Check if the node is a css comment to ignore the selector rule
* @param {object} node Node of postcss abstract syntax tree
* @param {string} type Type of css comment (next, start, end)
*/
return;
}
}
/**
* Check if the node is a css comment to ignore the selector rule
* @param {object} node Node of postcss abstract syntax tree
* @param {string} type Type of css comment (next, start, end)
*/
}, {
key: 'isIgnoreAnnotation',
value: function isIgnoreAnnotation(node, type) {
if (node && node.type === 'comment') {
switch (type) {
case 'next':
return node.text.includes(IGNORE_ANNOTATION_NEXT);
case 'start':
return node.text.includes(IGNORE_ANNOTATION_START);
case 'end':
return node.text.includes(IGNORE_ANNOTATION_END);
}
}
return false;
}
}, {
key: "isIgnoreAnnotation",
value: function isIgnoreAnnotation(node, type) {
if (node && node.type === 'comment') {
switch (type) {
case 'next':
return node.text.includes(IGNORE_ANNOTATION_NEXT);
/**
* Check if the node correspond to an empty css rule
* @param {object} node Node of postcss abstract syntax tree
*/
case 'start':
return node.text.includes(IGNORE_ANNOTATION_START);
}, {
key: 'isRuleEmpty',
value: function isRuleEmpty(node) {
if (node.type === 'decl' && !node.value || node.type === 'rule' && !node.selector || node.nodes && !node.nodes.length || node.type === 'atrule' && (!node.nodes && !node.params || !node.params && !node.nodes.length)) {
return true;
}
return false;
case 'end':
return node.text.includes(IGNORE_ANNOTATION_END);
}
}
/**
* Determine if the selector should be kept, based on the selectors found in the files
* @param {Set} selectorsInContent Set of css selectors found in the content files
* @param {Array} selectorsInRule Array of selectors
*/
return false;
}
/**
* Check if the node correspond to an empty css rule
* @param {object} node Node of postcss abstract syntax tree
*/
}, {
key: 'shouldKeepSelector',
value: function shouldKeepSelector(selectorsInContent, selectorsInRule) {
var _iteratorNormalCompletion11 = true;
var _didIteratorError11 = false;
var _iteratorError11 = undefined;
}, {
key: "isRuleEmpty",
value: function isRuleEmpty(node) {
if (node.type === 'decl' && !node.value || node.type === 'rule' && !node.selector || node.nodes && !node.nodes.length || node.type === 'atrule' && (!node.nodes && !node.params || !node.params && !node.nodes.length)) {
return true;
}
try {
for (var _iterator11 = selectorsInRule[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
var selector = _step11.value;
return false;
}
/**
* Determine if the selector should be kept, based on the selectors found in the files
* @param {Set} selectorsInContent Set of css selectors found in the content files
* @param {Array} selectorsInRule Array of selectors
*/
// pseudo class
var unescapedSelector = selector.replace(/\\/g, '');
}, {
key: "shouldKeepSelector",
value: function shouldKeepSelector(selectorsInContent, selectorsInRule) {
var _iteratorNormalCompletion11 = true;
var _didIteratorError11 = false;
var _iteratorError11 = undefined;
if (unescapedSelector.startsWith(':')) {
continue;
}
try {
for (var _iterator11 = selectorsInRule[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
var selector = _step11.value;
// pseudo class
var unescapedSelector = selector.replace(/\\/g, '');
// If the selector is whitelisted with children keep, simply
// returns true to keep all children selectors
if (this.isSelectorWhitelistedChildren(unescapedSelector)) {
return true;
}
if (unescapedSelector.startsWith(':')) {
continue;
} // If the selector is whitelisted with children keep, simply
// returns true to keep all children selectors
if (!(selectorsInContent.has(unescapedSelector) || CSS_WHITELIST.includes(unescapedSelector) || this.isSelectorWhitelisted(unescapedSelector))) {
return false;
}
}
} catch (err) {
_didIteratorError11 = true;
_iteratorError11 = err;
} finally {
try {
if (!_iteratorNormalCompletion11 && _iterator11.return) {
_iterator11.return();
}
} finally {
if (_didIteratorError11) {
throw _iteratorError11;
}
}
}
if (this.isSelectorWhitelistedChildren(unescapedSelector)) {
return true;
}
if (!(selectorsInContent.has(unescapedSelector) || CSS_WHITELIST.includes(unescapedSelector) || this.isSelectorWhitelisted(unescapedSelector))) {
return false;
}
}
} catch (err) {
_didIteratorError11 = true;
_iteratorError11 = err;
} finally {
try {
if (!_iteratorNormalCompletion11 && _iterator11.return != null) {
_iterator11.return();
}
} finally {
if (_didIteratorError11) {
throw _iteratorError11;
}
}
}
/**
* Check if the selector is whitelisted by the options whitelist or whitelistPatterns
* @param {string} selector css selector
*/
return true;
}
/**
* Check if the selector is whitelisted by the options whitelist or whitelistPatterns
* @param {string} selector css selector
*/
}, {
key: 'isSelectorWhitelisted',
value: function isSelectorWhitelisted(selector) {
return !!(CSS_WHITELIST.includes(selector) || this.options.whitelist && this.options.whitelist.some(function (v) {
return v === selector;
}) || this.options.whitelistPatterns && this.options.whitelistPatterns.some(function (v) {
return v.test(selector);
}));
}
}, {
key: "isSelectorWhitelisted",
value: function isSelectorWhitelisted(selector) {
return !!(CSS_WHITELIST.includes(selector) || this.options.whitelist && this.options.whitelist.some(function (v) {
return v === selector;
}) || this.options.whitelistPatterns && this.options.whitelistPatterns.some(function (v) {
return v.test(selector);
}));
}
/**
* Check if the selector is whitelisted by the whitelistPatternsChildren
* options element
*
* @param {string} selector
*/
/**
* Check if the selector is whitelisted by the whitelistPatternsChildren
* options element
*
* @param {string} selector
*/
}, {
key: "isSelectorWhitelistedChildren",
value: function isSelectorWhitelistedChildren(selector) {
return !!(this.options.whitelistPatternsChildren && this.options.whitelistPatternsChildren.some(function (v) {
return v.test(selector);
}));
}
}]);
}, {
key: 'isSelectorWhitelistedChildren',
value: function isSelectorWhitelistedChildren(selector) {
return !!(this.options.whitelistPatternsChildren && this.options.whitelistPatternsChildren.some(function (v) {
return v.test(selector);
}));
}
}]);
return Purgecss;
return Purgecss;
}();
module.exports = Purgecss;
{
"name": "purgecss",
"version": "1.1.0",
"version": "1.2.0",
"description": "Remove unused css selectors.",

@@ -48,25 +48,27 @@ "main": "./lib/purgecss.js",

"dependencies": {
"glob": "^7.1.2",
"postcss": "^7.0.0",
"postcss-selector-parser": "^5.0.0-rc.3",
"yargs": "^12.0.1"
"glob": "^7.1.3",
"postcss": "^7.0.14",
"postcss-selector-parser": "^6.0.0",
"yargs": "^13.2.2"
},
"devDependencies": {
"babel-eslint": "^8.2.5",
"babel-plugin-external-helpers": "^6.22.0",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-preset-env": "^1.7.0",
"babel-preset-flow": "^6.23.0",
"codacy-coverage": "^3.0.0",
"eslint": "^5.4.0",
"eslint-plugin-flowtype": "^2.50.0",
"flow-bin": "^0.79.0",
"jest": "^23.5.0",
"prettier": "^1.14.0",
"regenerator-runtime": "^0.12.0",
"rollup": "^0.64.0",
"rollup-plugin-babel": "^3.0.7",
"@babel/core": "^7.0.0",
"@babel/plugin-proposal-class-properties": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@babel/preset-flow": "^7.0.0",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^10.0.0",
"babel-jest": "^24.7.1",
"codacy-coverage": "^3.4.0",
"eslint": "^5.16.0",
"eslint-plugin-flowtype": "^3.5.0",
"flow-bin": "^0.96.0",
"jest": "^24.7.0",
"prettier": "^1.16.4",
"regenerator-runtime": "^0.13.0",
"rollup": "^1.9.0",
"rollup-plugin-babel": "^4.3.1",
"rollup-plugin-flow": "^1.1.1",
"rollup-plugin-node-builtins": "^2.1.2",
"rollup-plugin-node-resolve": "^3.3.0",
"rollup-plugin-node-resolve": "^4.1.0",
"rollup-watch": "^4.3.1"

@@ -73,0 +75,0 @@ },

@@ -65,3 +65,3 @@ # Purgecss

})
const result = purgecss.purge()
const result = purgeCss.purge()
```

@@ -84,3 +84,3 @@

})
const result = purgecss.purge()
const result = purgeCss.purge()
```

@@ -87,0 +87,0 @@

Sorry, the diff of this file is not supported yet

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