purgecss 1.2.0 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ # v1.4.0 - 2019-09-01
4
+
5
+ * Merged https://github.com/FullHuman/purgecss/commit/bc9f3b5b9d670832f0d1cca7bc7facfb253fb60b, ensure classes beginning with numbers are properly purged
6
+ * Merged https://github.com/FullHuman/purgecss/pull/214, fix font-face processing
7
+ * update dependencies
8
+
9
+ # v1.3.0 - 2019-04-20
10
+
11
+ * Merged https://github.com/FullHuman/purgecss/pull/183, adding `defaultExtractor` option
12
+ * remove ignore comment once purged, issue https://github.com/FullHuman/purgecss/issues/121
13
+
3
14
  # v1.2.0 - 2019-04-05
4
15
 
5
16
  * fix issue https://github.com/FullHuman/purgecss/issues/148, so the default extract is used for any file type that is not specified
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Purgecss
1
+ # PurgeCSS
2
2
 
3
3
  [![Build Status](https://travis-ci.org/FullHuman/purgecss.svg?branch=master)](https://travis-ci.org/FullHuman/purgecss)
4
4
  [![CircleCi](https://circleci.com/gh/FullHuman/purgecss/tree/master.svg?style=shield)]()
@@ -11,23 +11,23 @@
11
11
  [![license](https://img.shields.io/github/license/fullhuman/purgecss.svg)]() [![Greenkeeper badge](https://badges.greenkeeper.io/FullHuman/purgecss.svg)](https://greenkeeper.io/)
12
12
 
13
13
  <p align="center">
14
- <img src="./.assets/logo.png" height="200" width="200" alt="Purgecss logo"/>
14
+ <img src="./.assets/logo.png" height="200" width="200" alt="PurgeCSS logo"/>
15
15
  </p>
16
16
 
17
- ## What is purgecss?
17
+ ## What is PurgeCSS?
18
18
 
19
19
  When you are building a website, chances are that you are using a css framework
20
20
  like Bootstrap, Materializecss, Foundation, etc... But you will only use a small
21
21
  set of the framework and a lot of unused css styles will be included.
22
22
 
23
- This is where Purgecss comes into play. Purgecss analyzes your content and your
23
+ This is where PurgeCSS comes into play. PurgeCSS analyzes your content and your
24
24
  css files. Then it matches the selectors used in your files with the one in your
25
25
  content files. It removes unused selectors from your css, resulting in smaller
26
26
  css files.
27
27
 
28
28
  ## Documentation
29
29
 
30
- You can find the purgecss documentation
30
+ You can find the PurgeCSS documentation
31
31
  [on this website](https://www.purgecss.com).
32
32
 
33
33
  * [Configuration](https://www.purgecss.com/configuration)
@@ -112,11 +112,11 @@ conduct, and the process for submitting pull requests to us.
112
112
 
113
113
  ## Versioning
114
114
 
115
- Purgecss use [SemVer](http://semver.org/) for versioning.
115
+ PurgeCSS use [SemVer](http://semver.org/) for versioning.
116
116
 
117
117
  ## Acknowledgment
118
118
 
119
- Purgecss was originally thought as the v2 of purifycss. And because of it, it is
119
+ PurgeCSS was originally thought as the v2 of purifycss. And because of it, it is
120
120
  greatly inspired by it.\
121
121
  Some of the plugins such as purgecss-webpack-plugin are based on the purifycss plugin.\
122
122
  Below is the list of the purifycss repositories:
@@ -8,6 +8,7 @@ type RawContent = {
8
8
  declare type Options = {
9
9
  content: Array<string | RawContent>,
10
10
  css: Array<string | RawContent>,
11
+ defaultExtractor?: Object,
11
12
  extractors?: Array<ExtractorsObj>,
12
13
  whitelist?: Array<string>,
13
14
  whitelistPatterns?: Array<RegExp>,
@@ -36,4 +37,4 @@ declare type AtRules = {
36
37
  fontFace: Array<Object>
37
38
  }
38
39
 
39
- declare type IgnoreType = "next" | "start" | "end"
40
+ declare type IgnoreType = "next" | "start" | "end"
@@ -303,10 +303,28 @@ var substr = 'ab'.substr(-1) === 'b' ? function (str, start, len) {
303
303
  return str.substr(start, len);
304
304
  };
305
305
 
306
+ var DefaultExtractor =
307
+ /*#__PURE__*/
308
+ function () {
309
+ function DefaultExtractor() {
310
+ _classCallCheck(this, DefaultExtractor);
311
+ }
312
+
313
+ _createClass(DefaultExtractor, null, [{
314
+ key: "extract",
315
+ value: function extract(content) {
316
+ return content.match(/[A-Za-z0-9_-]+/g) || [];
317
+ }
318
+ }]);
319
+
320
+ return DefaultExtractor;
321
+ }();
322
+
306
323
  //
307
324
  var defaultOptions = {
308
325
  css: [],
309
326
  content: [],
327
+ defaultExtractor: DefaultExtractor,
310
328
  extractors: [],
311
329
  whitelist: [],
312
330
  output: undefined,
@@ -316,6 +334,7 @@ var defaultOptions = {
316
334
  rejected: false
317
335
  };
318
336
 
337
+ var IGNORE_ANNOTATION_CURRENT = 'purgecss ignore current';
319
338
  var IGNORE_ANNOTATION_NEXT = 'purgecss ignore';
320
339
  var IGNORE_ANNOTATION_START = 'purgecss start ignore';
321
340
  var IGNORE_ANNOTATION_END = 'purgecss end ignore';
@@ -336,22 +355,7 @@ var CSS_WHITELIST = ['*', '::-webkit-scrollbar', '::selection', ':root', '::befo
336
355
 
337
356
  var SELECTOR_STANDARD_TYPES = ['class', 'id', 'universal', 'pseudo'];
338
357
 
339
- var DefaultExtractor =
340
- /*#__PURE__*/
341
- function () {
342
- function DefaultExtractor() {
343
- _classCallCheck(this, DefaultExtractor);
344
- }
345
-
346
- _createClass(DefaultExtractor, null, [{
347
- key: "extract",
348
- value: function extract(content) {
349
- return content.match(/[A-Za-z0-9_-]+/g) || [];
350
- }
351
- }]);
352
-
353
- return DefaultExtractor;
354
- }();
358
+ var IS_NTH = /^:nth-/;
355
359
 
356
360
  var Purgecss =
357
361
  /*#__PURE__*/
@@ -374,7 +378,7 @@ function () {
374
378
 
375
379
  if (typeof options === 'string' || typeof options === 'undefined') options = this.loadConfigFile(options);
376
380
  this.checkOptions(options);
377
- this.options = Object.assign(defaultOptions, options);
381
+ this.options = Object.assign({}, defaultOptions, options);
378
382
  }
379
383
  /**
380
384
  * Load the configuration file from the path
@@ -389,7 +393,7 @@ function () {
389
393
  var options;
390
394
 
391
395
  try {
392
- var t = path.resolve(process.cwd(), pathConfig);
396
+ var t = path.join(process.cwd(), pathConfig);
393
397
  options = require(t);
394
398
  } catch (e) {
395
399
  throw new Error(ERROR_CONFIG_FILE_LOADING + e.message);
@@ -581,6 +585,16 @@ function () {
581
585
  }
582
586
  }
583
587
  }
588
+ /**
589
+ * Strips quotes at the end and at the end of a string
590
+ * @param {string} value the string to be stripped
591
+ */
592
+
593
+ }, {
594
+ key: "stripQuotes",
595
+ value: function stripQuotes(value) {
596
+ return value.replace(/(^["'])|(["']$)/g, '');
597
+ }
584
598
  /**
585
599
  * Extract the selectors present in the passed string using a purgecss extractor
586
600
  * @param {array} content Array of content
@@ -698,12 +712,14 @@ function () {
698
712
  key: "getFileExtractor",
699
713
  value: function getFileExtractor(filename) {
700
714
  var extractors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
701
- if (!extractors.length) return DefaultExtractor;
715
+ if (!extractors.length) return this.options.defaultExtractor;
702
716
  var extractorObj = extractors.find(function (extractor) {
703
717
  return extractor.extensions.find(function (ext) {
704
718
  return filename.endsWith(ext);
705
719
  });
706
- }) || DefaultExtractor;
720
+ }) || {
721
+ extractor: this.options.defaultExtractor
722
+ };
707
723
  return extractorObj.extractor;
708
724
  }
709
725
  /**
@@ -749,7 +765,15 @@ function () {
749
765
  }
750
766
 
751
767
  if (node.type === 'comment') {
752
- if (_this.isIgnoreAnnotation(node, 'start')) _this.ignore = true;else if (_this.isIgnoreAnnotation(node, 'end')) _this.ignore = false;
768
+ if (_this.isIgnoreAnnotation(node, 'start')) {
769
+ _this.ignore = true; // remove ignore annotation
770
+
771
+ node.remove();
772
+ } else if (_this.isIgnoreAnnotation(node, 'end')) {
773
+ _this.ignore = false; // remove ignore annotation
774
+
775
+ node.remove();
776
+ }
753
777
  }
754
778
  });
755
779
  }
@@ -765,7 +789,21 @@ function () {
765
789
  var _this2 = this;
766
790
 
767
791
  var annotation = node.prev();
768
- if (this.isIgnoreAnnotation(annotation, 'next') || this.ignore === true) return;
792
+ if (this.ignore) return;
793
+
794
+ if (typeof annotation !== 'undefined' && annotation.type === 'comment' && this.isIgnoreAnnotation(annotation, 'next')) {
795
+ annotation.remove();
796
+ return;
797
+ }
798
+
799
+ if (node.parent && node.parent.type === 'atrule' && node.parent.name === 'keyframes') {
800
+ return;
801
+ }
802
+
803
+ if (this.hasIgnoreAnnotation(node)) {
804
+ return;
805
+ }
806
+
769
807
  var keepSelector = true;
770
808
  node.selector = selectorParser(function (selectorsParsed) {
771
809
  selectorsParsed.walk(function (selector) {
@@ -787,10 +825,10 @@ function () {
787
825
  type = _step7$value.type,
788
826
  value = _step7$value.value;
789
827
 
790
- if (SELECTOR_STANDARD_TYPES.includes(type) && typeof value !== 'undefined' && /^\d/g.test(value) === false) {
828
+ if (SELECTOR_STANDARD_TYPES.includes(type) && typeof value !== 'undefined') {
791
829
  selectorsInRule.push(value);
792
- } else if (type === 'tag' && !/[+]|n|-|(even)|(odd)|^from$|^to$|^\d/.test(value)) {
793
- // test if we do not have a pseudo class parameter (e.g. 2n in :nth-child(2n))
830
+ } else if (type === 'tag' && !( // skip everything inside :nth-* pseudo selectors
831
+ selector.parent && selector.parent.type === 'pseudo' && IS_NTH.test(selector.parent.value))) {
794
832
  selectorsInRule.push(value);
795
833
  }
796
834
  }
@@ -860,7 +898,30 @@ function () {
860
898
 
861
899
  if (this.options.fontFace) {
862
900
  if (prop === 'font-family') {
863
- this.usedFontFaces.add(value);
901
+ var _iteratorNormalCompletion10 = true;
902
+ var _didIteratorError10 = false;
903
+ var _iteratorError10 = undefined;
904
+
905
+ try {
906
+ for (var _iterator10 = value.split(',')[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
907
+ var fontName = _step10.value;
908
+ var cleanedFontFace = this.stripQuotes(fontName.trim());
909
+ this.usedFontFaces.add(cleanedFontFace);
910
+ }
911
+ } catch (err) {
912
+ _didIteratorError10 = true;
913
+ _iteratorError10 = err;
914
+ } finally {
915
+ try {
916
+ if (!_iteratorNormalCompletion10 && _iterator10.return != null) {
917
+ _iterator10.return();
918
+ }
919
+ } finally {
920
+ if (_didIteratorError10) {
921
+ throw _iteratorError10;
922
+ }
923
+ }
924
+ }
864
925
  }
865
926
  }
866
927
  }
@@ -899,34 +960,34 @@ function () {
899
960
  }
900
961
 
901
962
  if (this.options.fontFace && node.name === 'font-face') {
902
- var _iteratorNormalCompletion10 = true;
903
- var _didIteratorError10 = false;
904
- var _iteratorError10 = undefined;
963
+ var _iteratorNormalCompletion11 = true;
964
+ var _didIteratorError11 = false;
965
+ var _iteratorError11 = undefined;
905
966
 
906
967
  try {
907
- for (var _iterator10 = node.nodes[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
908
- var _step10$value = _step10.value,
909
- prop = _step10$value.prop,
910
- value = _step10$value.value;
968
+ for (var _iterator11 = node.nodes[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
969
+ var _step11$value = _step11.value,
970
+ prop = _step11$value.prop,
971
+ value = _step11$value.value;
911
972
 
912
973
  if (prop === 'font-family') {
913
974
  this.atRules.fontFace.push({
914
- name: value,
975
+ name: this.stripQuotes(value),
915
976
  node: node
916
977
  });
917
978
  }
918
979
  }
919
980
  } catch (err) {
920
- _didIteratorError10 = true;
921
- _iteratorError10 = err;
981
+ _didIteratorError11 = true;
982
+ _iteratorError11 = err;
922
983
  } finally {
923
984
  try {
924
- if (!_iteratorNormalCompletion10 && _iterator10.return != null) {
925
- _iterator10.return();
985
+ if (!_iteratorNormalCompletion11 && _iterator11.return != null) {
986
+ _iterator11.return();
926
987
  }
927
988
  } finally {
928
- if (_didIteratorError10) {
929
- throw _iteratorError10;
989
+ if (_didIteratorError11) {
990
+ throw _iteratorError11;
930
991
  }
931
992
  }
932
993
  }
@@ -958,6 +1019,23 @@ function () {
958
1019
 
959
1020
  return false;
960
1021
  }
1022
+ /**
1023
+ * Check if the node has a css comment to ignore current selector rule
1024
+ * @param {object} rule Node of postcss abstract syntax tree
1025
+ */
1026
+
1027
+ }, {
1028
+ key: "hasIgnoreAnnotation",
1029
+ value: function hasIgnoreAnnotation(rule) {
1030
+ var found = false;
1031
+ rule.walkComments(function (node) {
1032
+ if (node && node.type === 'comment' && node.text.includes(IGNORE_ANNOTATION_CURRENT)) {
1033
+ found = true;
1034
+ node.remove();
1035
+ }
1036
+ });
1037
+ return found;
1038
+ }
961
1039
  /**
962
1040
  * Check if the node correspond to an empty css rule
963
1041
  * @param {object} node Node of postcss abstract syntax tree
@@ -981,13 +1059,13 @@ function () {
981
1059
  }, {
982
1060
  key: "shouldKeepSelector",
983
1061
  value: function shouldKeepSelector(selectorsInContent, selectorsInRule) {
984
- var _iteratorNormalCompletion11 = true;
985
- var _didIteratorError11 = false;
986
- var _iteratorError11 = undefined;
1062
+ var _iteratorNormalCompletion12 = true;
1063
+ var _didIteratorError12 = false;
1064
+ var _iteratorError12 = undefined;
987
1065
 
988
1066
  try {
989
- for (var _iterator11 = selectorsInRule[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
990
- var selector = _step11.value;
1067
+ for (var _iterator12 = selectorsInRule[Symbol.iterator](), _step12; !(_iteratorNormalCompletion12 = (_step12 = _iterator12.next()).done); _iteratorNormalCompletion12 = true) {
1068
+ var selector = _step12.value;
991
1069
  // pseudo class
992
1070
  var unescapedSelector = selector.replace(/\\/g, '');
993
1071
 
@@ -1006,16 +1084,16 @@ function () {
1006
1084
  }
1007
1085
  }
1008
1086
  } catch (err) {
1009
- _didIteratorError11 = true;
1010
- _iteratorError11 = err;
1087
+ _didIteratorError12 = true;
1088
+ _iteratorError12 = err;
1011
1089
  } finally {
1012
1090
  try {
1013
- if (!_iteratorNormalCompletion11 && _iterator11.return != null) {
1014
- _iterator11.return();
1091
+ if (!_iteratorNormalCompletion12 && _iterator12.return != null) {
1092
+ _iterator12.return();
1015
1093
  }
1016
1094
  } finally {
1017
- if (_didIteratorError11) {
1018
- throw _iteratorError11;
1095
+ if (_didIteratorError12) {
1096
+ throw _iteratorError12;
1019
1097
  }
1020
1098
  }
1021
1099
  }
package/lib/purgecss.js CHANGED
@@ -307,10 +307,28 @@ var substr = 'ab'.substr(-1) === 'b' ? function (str, start, len) {
307
307
  return str.substr(start, len);
308
308
  };
309
309
 
310
+ var DefaultExtractor =
311
+ /*#__PURE__*/
312
+ function () {
313
+ function DefaultExtractor() {
314
+ _classCallCheck(this, DefaultExtractor);
315
+ }
316
+
317
+ _createClass(DefaultExtractor, null, [{
318
+ key: "extract",
319
+ value: function extract(content) {
320
+ return content.match(/[A-Za-z0-9_-]+/g) || [];
321
+ }
322
+ }]);
323
+
324
+ return DefaultExtractor;
325
+ }();
326
+
310
327
  //
311
328
  var defaultOptions = {
312
329
  css: [],
313
330
  content: [],
331
+ defaultExtractor: DefaultExtractor,
314
332
  extractors: [],
315
333
  whitelist: [],
316
334
  output: undefined,
@@ -320,6 +338,7 @@ var defaultOptions = {
320
338
  rejected: false
321
339
  };
322
340
 
341
+ var IGNORE_ANNOTATION_CURRENT = 'purgecss ignore current';
323
342
  var IGNORE_ANNOTATION_NEXT = 'purgecss ignore';
324
343
  var IGNORE_ANNOTATION_START = 'purgecss start ignore';
325
344
  var IGNORE_ANNOTATION_END = 'purgecss end ignore';
@@ -340,22 +359,7 @@ var CSS_WHITELIST = ['*', '::-webkit-scrollbar', '::selection', ':root', '::befo
340
359
 
341
360
  var SELECTOR_STANDARD_TYPES = ['class', 'id', 'universal', 'pseudo'];
342
361
 
343
- var DefaultExtractor =
344
- /*#__PURE__*/
345
- function () {
346
- function DefaultExtractor() {
347
- _classCallCheck(this, DefaultExtractor);
348
- }
349
-
350
- _createClass(DefaultExtractor, null, [{
351
- key: "extract",
352
- value: function extract(content) {
353
- return content.match(/[A-Za-z0-9_-]+/g) || [];
354
- }
355
- }]);
356
-
357
- return DefaultExtractor;
358
- }();
362
+ var IS_NTH = /^:nth-/;
359
363
 
360
364
  var Purgecss =
361
365
  /*#__PURE__*/
@@ -378,7 +382,7 @@ function () {
378
382
 
379
383
  if (typeof options === 'string' || typeof options === 'undefined') options = this.loadConfigFile(options);
380
384
  this.checkOptions(options);
381
- this.options = Object.assign(defaultOptions, options);
385
+ this.options = Object.assign({}, defaultOptions, options);
382
386
  }
383
387
  /**
384
388
  * Load the configuration file from the path
@@ -393,7 +397,7 @@ function () {
393
397
  var options;
394
398
 
395
399
  try {
396
- var t = path.resolve(process.cwd(), pathConfig);
400
+ var t = path.join(process.cwd(), pathConfig);
397
401
  options = require(t);
398
402
  } catch (e) {
399
403
  throw new Error(ERROR_CONFIG_FILE_LOADING + e.message);
@@ -585,6 +589,16 @@ function () {
585
589
  }
586
590
  }
587
591
  }
592
+ /**
593
+ * Strips quotes at the end and at the end of a string
594
+ * @param {string} value the string to be stripped
595
+ */
596
+
597
+ }, {
598
+ key: "stripQuotes",
599
+ value: function stripQuotes(value) {
600
+ return value.replace(/(^["'])|(["']$)/g, '');
601
+ }
588
602
  /**
589
603
  * Extract the selectors present in the passed string using a purgecss extractor
590
604
  * @param {array} content Array of content
@@ -702,12 +716,14 @@ function () {
702
716
  key: "getFileExtractor",
703
717
  value: function getFileExtractor(filename) {
704
718
  var extractors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
705
- if (!extractors.length) return DefaultExtractor;
719
+ if (!extractors.length) return this.options.defaultExtractor;
706
720
  var extractorObj = extractors.find(function (extractor) {
707
721
  return extractor.extensions.find(function (ext) {
708
722
  return filename.endsWith(ext);
709
723
  });
710
- }) || DefaultExtractor;
724
+ }) || {
725
+ extractor: this.options.defaultExtractor
726
+ };
711
727
  return extractorObj.extractor;
712
728
  }
713
729
  /**
@@ -753,7 +769,15 @@ function () {
753
769
  }
754
770
 
755
771
  if (node.type === 'comment') {
756
- if (_this.isIgnoreAnnotation(node, 'start')) _this.ignore = true;else if (_this.isIgnoreAnnotation(node, 'end')) _this.ignore = false;
772
+ if (_this.isIgnoreAnnotation(node, 'start')) {
773
+ _this.ignore = true; // remove ignore annotation
774
+
775
+ node.remove();
776
+ } else if (_this.isIgnoreAnnotation(node, 'end')) {
777
+ _this.ignore = false; // remove ignore annotation
778
+
779
+ node.remove();
780
+ }
757
781
  }
758
782
  });
759
783
  }
@@ -769,7 +793,21 @@ function () {
769
793
  var _this2 = this;
770
794
 
771
795
  var annotation = node.prev();
772
- if (this.isIgnoreAnnotation(annotation, 'next') || this.ignore === true) return;
796
+ if (this.ignore) return;
797
+
798
+ if (typeof annotation !== 'undefined' && annotation.type === 'comment' && this.isIgnoreAnnotation(annotation, 'next')) {
799
+ annotation.remove();
800
+ return;
801
+ }
802
+
803
+ if (node.parent && node.parent.type === 'atrule' && node.parent.name === 'keyframes') {
804
+ return;
805
+ }
806
+
807
+ if (this.hasIgnoreAnnotation(node)) {
808
+ return;
809
+ }
810
+
773
811
  var keepSelector = true;
774
812
  node.selector = selectorParser(function (selectorsParsed) {
775
813
  selectorsParsed.walk(function (selector) {
@@ -791,10 +829,10 @@ function () {
791
829
  type = _step7$value.type,
792
830
  value = _step7$value.value;
793
831
 
794
- if (SELECTOR_STANDARD_TYPES.includes(type) && typeof value !== 'undefined' && /^\d/g.test(value) === false) {
832
+ if (SELECTOR_STANDARD_TYPES.includes(type) && typeof value !== 'undefined') {
795
833
  selectorsInRule.push(value);
796
- } else if (type === 'tag' && !/[+]|n|-|(even)|(odd)|^from$|^to$|^\d/.test(value)) {
797
- // test if we do not have a pseudo class parameter (e.g. 2n in :nth-child(2n))
834
+ } else if (type === 'tag' && !( // skip everything inside :nth-* pseudo selectors
835
+ selector.parent && selector.parent.type === 'pseudo' && IS_NTH.test(selector.parent.value))) {
798
836
  selectorsInRule.push(value);
799
837
  }
800
838
  }
@@ -864,7 +902,30 @@ function () {
864
902
 
865
903
  if (this.options.fontFace) {
866
904
  if (prop === 'font-family') {
867
- this.usedFontFaces.add(value);
905
+ var _iteratorNormalCompletion10 = true;
906
+ var _didIteratorError10 = false;
907
+ var _iteratorError10 = undefined;
908
+
909
+ try {
910
+ for (var _iterator10 = value.split(',')[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
911
+ var fontName = _step10.value;
912
+ var cleanedFontFace = this.stripQuotes(fontName.trim());
913
+ this.usedFontFaces.add(cleanedFontFace);
914
+ }
915
+ } catch (err) {
916
+ _didIteratorError10 = true;
917
+ _iteratorError10 = err;
918
+ } finally {
919
+ try {
920
+ if (!_iteratorNormalCompletion10 && _iterator10.return != null) {
921
+ _iterator10.return();
922
+ }
923
+ } finally {
924
+ if (_didIteratorError10) {
925
+ throw _iteratorError10;
926
+ }
927
+ }
928
+ }
868
929
  }
869
930
  }
870
931
  }
@@ -903,34 +964,34 @@ function () {
903
964
  }
904
965
 
905
966
  if (this.options.fontFace && node.name === 'font-face') {
906
- var _iteratorNormalCompletion10 = true;
907
- var _didIteratorError10 = false;
908
- var _iteratorError10 = undefined;
967
+ var _iteratorNormalCompletion11 = true;
968
+ var _didIteratorError11 = false;
969
+ var _iteratorError11 = undefined;
909
970
 
910
971
  try {
911
- for (var _iterator10 = node.nodes[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
912
- var _step10$value = _step10.value,
913
- prop = _step10$value.prop,
914
- value = _step10$value.value;
972
+ for (var _iterator11 = node.nodes[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
973
+ var _step11$value = _step11.value,
974
+ prop = _step11$value.prop,
975
+ value = _step11$value.value;
915
976
 
916
977
  if (prop === 'font-family') {
917
978
  this.atRules.fontFace.push({
918
- name: value,
979
+ name: this.stripQuotes(value),
919
980
  node: node
920
981
  });
921
982
  }
922
983
  }
923
984
  } catch (err) {
924
- _didIteratorError10 = true;
925
- _iteratorError10 = err;
985
+ _didIteratorError11 = true;
986
+ _iteratorError11 = err;
926
987
  } finally {
927
988
  try {
928
- if (!_iteratorNormalCompletion10 && _iterator10.return != null) {
929
- _iterator10.return();
989
+ if (!_iteratorNormalCompletion11 && _iterator11.return != null) {
990
+ _iterator11.return();
930
991
  }
931
992
  } finally {
932
- if (_didIteratorError10) {
933
- throw _iteratorError10;
993
+ if (_didIteratorError11) {
994
+ throw _iteratorError11;
934
995
  }
935
996
  }
936
997
  }
@@ -962,6 +1023,23 @@ function () {
962
1023
 
963
1024
  return false;
964
1025
  }
1026
+ /**
1027
+ * Check if the node has a css comment to ignore current selector rule
1028
+ * @param {object} rule Node of postcss abstract syntax tree
1029
+ */
1030
+
1031
+ }, {
1032
+ key: "hasIgnoreAnnotation",
1033
+ value: function hasIgnoreAnnotation(rule) {
1034
+ var found = false;
1035
+ rule.walkComments(function (node) {
1036
+ if (node && node.type === 'comment' && node.text.includes(IGNORE_ANNOTATION_CURRENT)) {
1037
+ found = true;
1038
+ node.remove();
1039
+ }
1040
+ });
1041
+ return found;
1042
+ }
965
1043
  /**
966
1044
  * Check if the node correspond to an empty css rule
967
1045
  * @param {object} node Node of postcss abstract syntax tree
@@ -985,13 +1063,13 @@ function () {
985
1063
  }, {
986
1064
  key: "shouldKeepSelector",
987
1065
  value: function shouldKeepSelector(selectorsInContent, selectorsInRule) {
988
- var _iteratorNormalCompletion11 = true;
989
- var _didIteratorError11 = false;
990
- var _iteratorError11 = undefined;
1066
+ var _iteratorNormalCompletion12 = true;
1067
+ var _didIteratorError12 = false;
1068
+ var _iteratorError12 = undefined;
991
1069
 
992
1070
  try {
993
- for (var _iterator11 = selectorsInRule[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
994
- var selector = _step11.value;
1071
+ for (var _iterator12 = selectorsInRule[Symbol.iterator](), _step12; !(_iteratorNormalCompletion12 = (_step12 = _iterator12.next()).done); _iteratorNormalCompletion12 = true) {
1072
+ var selector = _step12.value;
995
1073
  // pseudo class
996
1074
  var unescapedSelector = selector.replace(/\\/g, '');
997
1075
 
@@ -1010,16 +1088,16 @@ function () {
1010
1088
  }
1011
1089
  }
1012
1090
  } catch (err) {
1013
- _didIteratorError11 = true;
1014
- _iteratorError11 = err;
1091
+ _didIteratorError12 = true;
1092
+ _iteratorError12 = err;
1015
1093
  } finally {
1016
1094
  try {
1017
- if (!_iteratorNormalCompletion11 && _iterator11.return != null) {
1018
- _iterator11.return();
1095
+ if (!_iteratorNormalCompletion12 && _iterator12.return != null) {
1096
+ _iterator12.return();
1019
1097
  }
1020
1098
  } finally {
1021
- if (_didIteratorError11) {
1022
- throw _iteratorError11;
1099
+ if (_didIteratorError12) {
1100
+ throw _iteratorError12;
1023
1101
  }
1024
1102
  }
1025
1103
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "purgecss",
3
- "version": "1.2.0",
3
+ "version": "1.4.2",
4
4
  "description": "Remove unused css selectors.",
5
5
  "main": "./lib/purgecss.js",
6
6
  "module": "./lib/purgecss.es.js",
@@ -18,12 +18,12 @@
18
18
  ],
19
19
  "bin": "./bin/purgecss",
20
20
  "scripts": {
21
- "test": "npx jest __tests__/.+.test.js",
21
+ "test": "jest __tests__/.+.test.js",
22
22
  "dev": "rollup -c rollup.config.js -w",
23
23
  "build": "rollup -c rollup.config.js",
24
- "flow": "npx flow",
25
- "lint": "npx eslint -c .eslintrc src/",
26
- "prettier": "npx prettier --write --print-width 100 --tab-width 4 --no-semi --single-quote '{src,__{tests,mocks}__}/**/*.js'"
24
+ "flow": "flow",
25
+ "lint": "eslint -c .eslintrc src/",
26
+ "prettier": "prettier --write --print-width 100 --tab-width 4 --no-semi --single-quote '{src,__{tests,mocks}__}/**/*.js'"
27
27
  },
28
28
  "repository": {
29
29
  "type": "git",
@@ -48,32 +48,34 @@
48
48
  "glob": "^7.1.3",
49
49
  "postcss": "^7.0.14",
50
50
  "postcss-selector-parser": "^6.0.0",
51
- "yargs": "^13.2.2"
51
+ "yargs": "^14.0.0"
52
52
  },
53
53
  "devDependencies": {
54
- "@babel/core": "^7.0.0",
55
- "@babel/plugin-proposal-class-properties": "^7.0.0",
56
- "@babel/preset-env": "^7.0.0",
54
+ "@babel/core": "^7.6.4",
55
+ "@babel/plugin-proposal-class-properties": "^7.5.5",
56
+ "@babel/preset-env": "^7.6.3",
57
57
  "@babel/preset-flow": "^7.0.0",
58
58
  "babel-core": "^7.0.0-bridge.0",
59
- "babel-eslint": "^10.0.0",
60
- "babel-jest": "^24.7.1",
59
+ "babel-eslint": "^10.0.3",
60
+ "babel-jest": "^24.9.0",
61
61
  "codacy-coverage": "^3.4.0",
62
- "eslint": "^5.16.0",
63
- "eslint-plugin-flowtype": "^3.5.0",
64
- "flow-bin": "^0.96.0",
65
- "jest": "^24.7.0",
66
- "prettier": "^1.16.4",
67
- "regenerator-runtime": "^0.13.0",
68
- "rollup": "^1.9.0",
69
- "rollup-plugin-babel": "^4.3.1",
62
+ "eslint": "^6.6.0",
63
+ "eslint-plugin-flowtype": "^4.3.0",
64
+ "flow-bin": "^0.113.0",
65
+ "jest": "^24.9.0",
66
+ "prettier": "^1.18.2",
67
+ "regenerator-runtime": "^0.13.3",
68
+ "rollup": "^1.26.0",
69
+ "rollup-plugin-babel": "^4.3.3",
70
70
  "rollup-plugin-flow": "^1.1.1",
71
71
  "rollup-plugin-node-builtins": "^2.1.2",
72
- "rollup-plugin-node-resolve": "^4.1.0",
73
- "rollup-watch": "^4.3.1"
72
+ "rollup-plugin-node-resolve": "^5.2.0"
74
73
  },
75
74
  "engines": {
76
75
  "npm": ">=5.2.0",
77
76
  "node": ">=4.4.0"
77
+ },
78
+ "funding": {
79
+ "url": "https://github.com/sponsors/Ffloriel"
78
80
  }
79
81
  }