index.js 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. 'use strict';
  2. const selectorParser = require('postcss-selector-parser');
  3. /**
  4. * @param {string} selectors
  5. * @param {selectorParser.SyncProcessor<void>} callback
  6. * @return {string}
  7. */
  8. function parseSelectors(selectors, callback) {
  9. return selectorParser(callback).processSync(selectors);
  10. }
  11. /**
  12. * @param {import('postcss').Rule} rule
  13. * @return {string}
  14. */
  15. function unique(rule) {
  16. const selector = [...new Set(rule.selectors)];
  17. selector.sort();
  18. return selector.join();
  19. }
  20. /**
  21. * @type {import('postcss').PluginCreator<void>}
  22. * @return {import('postcss').Plugin}
  23. */
  24. function pluginCreator() {
  25. return {
  26. postcssPlugin: 'postcss-unique-selectors',
  27. OnceExit(css) {
  28. css.walkRules((nodes) => {
  29. /** @type {string[]} */
  30. let comments = [];
  31. /** @type {selectorParser.SyncProcessor<void>} */
  32. const removeAndSaveComments = (selNode) => {
  33. selNode.walk((sel) => {
  34. if (sel.type === 'comment') {
  35. comments.push(sel.value);
  36. sel.remove();
  37. return;
  38. } else {
  39. return;
  40. }
  41. });
  42. };
  43. if (nodes.raws.selector && nodes.raws.selector.raw) {
  44. parseSelectors(nodes.raws.selector.raw, removeAndSaveComments);
  45. nodes.raws.selector.raw = unique(nodes);
  46. }
  47. nodes.selector = parseSelectors(nodes.selector, removeAndSaveComments);
  48. nodes.selector = unique(nodes);
  49. nodes.selectors = nodes.selectors.concat(comments);
  50. });
  51. },
  52. };
  53. }
  54. pluginCreator.postcss = true;
  55. module.exports = pluginCreator;