index.es.mjs 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import postcss from 'postcss';
  2. import selectorParser from 'postcss-selector-parser';
  3. var index = postcss.plugin('postcss-dir-pseudo-class', opts => {
  4. const dir = Object(opts).dir;
  5. const preserve = Boolean(Object(opts).preserve);
  6. return root => {
  7. // walk rules using the :dir pseudo-class
  8. root.walkRules(/:dir\([^\)]*\)/, rule => {
  9. let currentRule = rule; // conditionally preserve the original rule
  10. if (preserve) {
  11. currentRule = rule.cloneBefore();
  12. } // update the rule selector
  13. currentRule.selector = selectorParser(selectors => {
  14. // for each (comma separated) selector
  15. selectors.nodes.forEach(selector => {
  16. // walk all selector nodes that are :dir pseudo-classes
  17. selector.walk(node => {
  18. if ('pseudo' === node.type && ':dir' === node.value) {
  19. // previous and next selector nodes
  20. const prev = node.prev();
  21. const next = node.next();
  22. const prevIsSpaceCombinator = prev && prev.type && 'combinator' === prev.type && ' ' === prev.value;
  23. const nextIsSpaceCombinator = next && next.type && 'combinator' === next.type && ' ' === next.value; // preserve the selector tree
  24. if (prevIsSpaceCombinator && (nextIsSpaceCombinator || !next)) {
  25. node.replaceWith(selectorParser.universal());
  26. } else {
  27. node.remove();
  28. } // conditionally prepend a combinator before inserting the [dir] attribute
  29. const first = selector.nodes[0];
  30. const firstIsSpaceCombinator = first && 'combinator' === first.type && ' ' === first.value;
  31. const firstIsHtml = first && 'tag' === first.type && 'html' === first.value;
  32. const firstIsRoot = first && 'pseudo' === first.type && ':root' === first.value;
  33. if (first && !firstIsHtml && !firstIsRoot && !firstIsSpaceCombinator) {
  34. selector.prepend(selectorParser.combinator({
  35. value: ' '
  36. }));
  37. } // value of the :dir pseudo-class
  38. const value = node.nodes.toString(); // whether :dir matches the presumed direction
  39. const isdir = dir === value; // [dir] attribute
  40. const dirAttr = selectorParser.attribute({
  41. attribute: 'dir',
  42. operator: '=',
  43. quoteMark: '"',
  44. value: `"${value}"`
  45. }); // not[dir] attribute
  46. const notDirAttr = selectorParser.pseudo({
  47. value: `${firstIsHtml || firstIsRoot ? '' : 'html'}:not`
  48. });
  49. notDirAttr.append(selectorParser.attribute({
  50. attribute: 'dir',
  51. operator: '=',
  52. quoteMark: '"',
  53. value: `"${'ltr' === value ? 'rtl' : 'ltr'}"`
  54. }));
  55. if (isdir) {
  56. // if the direction is presumed
  57. if (firstIsHtml) {
  58. // insert :root after html tag
  59. selector.insertAfter(first, notDirAttr);
  60. } else {
  61. // prepend :root
  62. selector.prepend(notDirAttr);
  63. }
  64. } else if (firstIsHtml) {
  65. // otherwise, insert dir attribute after html tag
  66. selector.insertAfter(first, dirAttr);
  67. } else {
  68. // otherwise, prepend the dir attribute
  69. selector.prepend(dirAttr);
  70. }
  71. }
  72. });
  73. });
  74. }).processSync(currentRule.selector);
  75. });
  76. };
  77. });
  78. export default index;
  79. //# sourceMappingURL=index.es.mjs.map