remove-empty-rulesets.js 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. module.exports = (function() {
  2. function processNode(node) {
  3. removeEmptyRulesets(node);
  4. mergeAdjacentWhitespace(node);
  5. }
  6. function removeEmptyRulesets(stylesheet) {
  7. stylesheet.forEach('ruleset', function(ruleset, i) {
  8. var block = ruleset.first('block');
  9. processNode(block);
  10. if (isEmptyBlock(block)) stylesheet.remove(i);
  11. });
  12. }
  13. /**
  14. * Removing ruleset nodes from tree may result in two adjacent whitespace
  15. * nodes which is not correct AST:
  16. * [space, ruleset, space] => [space, space]
  17. * To ensure correctness of further processing we should merge such nodes
  18. * into one:
  19. * [space, space] => [space]
  20. */
  21. function mergeAdjacentWhitespace(node) {
  22. var i = node.content.length - 1;
  23. while (i-- > 0) {
  24. if (node.get(i).is('space') && node.get(i + 1).is('space')) {
  25. node.get(i).content += node.get(i + 1).content;
  26. node.remove(i + 1);
  27. }
  28. }
  29. }
  30. /**
  31. * Block is considered empty when it has nothing but spaces.
  32. */
  33. function isEmptyBlock(node) {
  34. if (!node.length) return true;
  35. return !node.content.some(function(node) {
  36. return !node.is('space');
  37. });
  38. }
  39. return {
  40. name: 'remove-empty-rulesets',
  41. runBefore: 'block-indent',
  42. syntax: ['css', 'less', 'sass', 'scss'],
  43. accepts: { boolean: [true] },
  44. /**
  45. * Remove rulesets with no declarations.
  46. *
  47. * @param {String} node
  48. */
  49. process: function(node) {
  50. if (!node.is('stylesheet')) return;
  51. processNode(node);
  52. },
  53. detectDefault: true,
  54. /**
  55. * Detects the value of an option at the tree node.
  56. * This option is treated as `true` by default, but any trailing space would invalidate it.
  57. *
  58. * @param {node} node
  59. */
  60. detect: function(node) {
  61. if (!node.is('atrulers') && !node.is('block')) return;
  62. if (node.length === 0 ||
  63. (node.length === 1 && node.first().is('space'))) {
  64. return false;
  65. }
  66. }
  67. };
  68. })();