index.cjs.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. 'use strict';
  2. function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
  3. var postcss = require('postcss');
  4. var postcss__default = _interopDefault(postcss);
  5. function shiftNodesBeforeParent(node) {
  6. const parent = node.parent;
  7. const index = parent.index(node); // conditionally move previous siblings into a clone of the parent
  8. if (index) {
  9. parent.cloneBefore().removeAll().append(parent.nodes.slice(0, index));
  10. } // move the current node before the parent (and after the conditional clone)
  11. parent.before(node);
  12. return parent;
  13. }
  14. function cleanupParent(parent) {
  15. if (!parent.nodes.length) {
  16. parent.remove();
  17. }
  18. }
  19. // a valid selector is an ampersand followed by a non-word character or nothing
  20. var validSelector = /&(?:[^\w-|]|$)/;
  21. const replaceable = /&/g;
  22. function mergeSelectors(fromSelectors, toSelectors) {
  23. return fromSelectors.reduce((selectors, fromSelector) => selectors.concat(toSelectors.map(toSelector => toSelector.replace(replaceable, fromSelector))), []);
  24. }
  25. function transformRuleWithinRule(node) {
  26. // move previous siblings and the node to before the parent
  27. const parent = shiftNodesBeforeParent(node); // update the selectors of the node to be merged with the parent
  28. node.selectors = mergeSelectors(parent.selectors, node.selectors); // merge similar rules back together
  29. // eslint-disable-next-line no-extra-parens
  30. const areSameRule = node.type === 'rule' && parent.type === 'rule' && node.selector === parent.selector || node.type === 'atrule' && parent.type === 'atrule' && node.params === parent.params;
  31. if (areSameRule) {
  32. node.append(...parent.nodes);
  33. } // conditionally cleanup an empty parent rule
  34. cleanupParent(parent);
  35. }
  36. const isRuleWithinRule = node => node.type === 'rule' && Object(node.parent).type === 'rule' && node.selectors.every(selector => selector.trim().lastIndexOf('&') === 0 && validSelector.test(selector));
  37. const comma = postcss.list.comma;
  38. function transformNestRuleWithinRule(node) {
  39. // move previous siblings and the node to before the parent
  40. const parent = shiftNodesBeforeParent(node); // clone the parent as a new rule with children appended to it
  41. const rule = parent.clone().removeAll().append(node.nodes); // replace the node with the new rule
  42. node.replaceWith(rule); // update the selectors of the node to be merged with the parent
  43. rule.selectors = mergeSelectors(parent.selectors, comma(node.params)); // conditionally cleanup an empty parent rule
  44. cleanupParent(parent); // walk the children of the new rule
  45. walk(rule);
  46. }
  47. const isNestRuleWithinRule = node => node.type === 'atrule' && node.name === 'nest' && Object(node.parent).type === 'rule' && comma(node.params).every(selector => selector.split('&').length === 2 && validSelector.test(selector));
  48. var validAtrules = ['document', 'media', 'supports'];
  49. /*
  50. * DEPRECATED: In v7.0.0 these features will be removed as they are not part of
  51. * the nesting proposal.
  52. */
  53. function atruleWithinRule(node) {
  54. // move previous siblings and the node to before the parent
  55. const parent = shiftNodesBeforeParent(node); // clone the parent as a new rule with children appended to it
  56. const rule = parent.clone().removeAll().append(node.nodes); // append the new rule to the node
  57. node.append(rule); // conditionally cleanup an empty parent rule
  58. cleanupParent(parent); // walk the children of the new rule
  59. walk(rule);
  60. }
  61. const isAtruleWithinRule = node => node.type === 'atrule' && validAtrules.indexOf(node.name) !== -1 && Object(node.parent).type === 'rule';
  62. const comma$1 = postcss.list.comma;
  63. function mergeParams(fromParams, toParams) {
  64. return comma$1(fromParams).map(params1 => comma$1(toParams).map(params2 => `${params1} and ${params2}`).join(', ')).join(', ');
  65. }
  66. /*
  67. * DEPRECATED: In v7.0.0 these features will be removed as they are not part of
  68. * the nesting proposal.
  69. */
  70. function transformAtruleWithinAtrule(node) {
  71. // move previous siblings and the node to before the parent
  72. const parent = shiftNodesBeforeParent(node); // update the params of the node to be merged with the parent
  73. node.params = mergeParams(parent.params, node.params); // conditionally cleanup an empty parent rule
  74. cleanupParent(parent);
  75. }
  76. const isAtruleWithinAtrule = node => node.type === 'atrule' && validAtrules.indexOf(node.name) !== -1 && Object(node.parent).type === 'atrule' && node.name === node.parent.name;
  77. function walk(node) {
  78. node.nodes.slice(0).forEach(child => {
  79. if (child.parent === node) {
  80. if (isRuleWithinRule(child)) {
  81. transformRuleWithinRule(child);
  82. } else if (isNestRuleWithinRule(child)) {
  83. transformNestRuleWithinRule(child);
  84. } else if (isAtruleWithinRule(child)) {
  85. atruleWithinRule(child);
  86. } else if (isAtruleWithinAtrule(child)) {
  87. transformAtruleWithinAtrule(child);
  88. }
  89. if (Object(child.nodes).length) {
  90. walk(child);
  91. }
  92. }
  93. });
  94. }
  95. var index = postcss__default.plugin('postcss-nesting', () => walk);
  96. module.exports = index;
  97. //# sourceMappingURL=index.cjs.js.map