Rule.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. var hasOwnProperty = Object.prototype.hasOwnProperty;
  2. var walk = require('css-tree').walk;
  3. function cleanUnused(selectorList, usageData) {
  4. selectorList.children.each(function(selector, item, list) {
  5. var shouldRemove = false;
  6. walk(selector, function(node) {
  7. // ignore nodes in nested selectors
  8. if (this.selector === null || this.selector === selectorList) {
  9. switch (node.type) {
  10. case 'SelectorList':
  11. // TODO: remove toLowerCase when pseudo selectors will be normalized
  12. // ignore selectors inside :not()
  13. if (this['function'] === null || this['function'].name.toLowerCase() !== 'not') {
  14. if (cleanUnused(node, usageData)) {
  15. shouldRemove = true;
  16. }
  17. }
  18. break;
  19. case 'ClassSelector':
  20. if (usageData.whitelist !== null &&
  21. usageData.whitelist.classes !== null &&
  22. !hasOwnProperty.call(usageData.whitelist.classes, node.name)) {
  23. shouldRemove = true;
  24. }
  25. if (usageData.blacklist !== null &&
  26. usageData.blacklist.classes !== null &&
  27. hasOwnProperty.call(usageData.blacklist.classes, node.name)) {
  28. shouldRemove = true;
  29. }
  30. break;
  31. case 'IdSelector':
  32. if (usageData.whitelist !== null &&
  33. usageData.whitelist.ids !== null &&
  34. !hasOwnProperty.call(usageData.whitelist.ids, node.name)) {
  35. shouldRemove = true;
  36. }
  37. if (usageData.blacklist !== null &&
  38. usageData.blacklist.ids !== null &&
  39. hasOwnProperty.call(usageData.blacklist.ids, node.name)) {
  40. shouldRemove = true;
  41. }
  42. break;
  43. case 'TypeSelector':
  44. // TODO: remove toLowerCase when type selectors will be normalized
  45. // ignore universal selectors
  46. if (node.name.charAt(node.name.length - 1) !== '*') {
  47. if (usageData.whitelist !== null &&
  48. usageData.whitelist.tags !== null &&
  49. !hasOwnProperty.call(usageData.whitelist.tags, node.name.toLowerCase())) {
  50. shouldRemove = true;
  51. }
  52. if (usageData.blacklist !== null &&
  53. usageData.blacklist.tags !== null &&
  54. hasOwnProperty.call(usageData.blacklist.tags, node.name.toLowerCase())) {
  55. shouldRemove = true;
  56. }
  57. }
  58. break;
  59. }
  60. }
  61. });
  62. if (shouldRemove) {
  63. list.remove(item);
  64. }
  65. });
  66. return selectorList.children.isEmpty();
  67. }
  68. module.exports = function cleanRuleset(node, item, list, options) {
  69. var usageData = options.usage;
  70. if (usageData && (usageData.whitelist !== null || usageData.blacklist !== null)) {
  71. cleanUnused(node.prelude, usageData);
  72. }
  73. if (node.prelude.children.isEmpty() ||
  74. node.block.children.isEmpty()) {
  75. list.remove(item);
  76. }
  77. };