summaryrefslogtreecommitdiff
path: root/node_modules/postcss-unique-selectors/src/index.js
blob: 39cd52fa80626f39d830bed0010fd7cca98bd3e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
'use strict';
const selectorParser = require('postcss-selector-parser');

/**
 * @param {string} selectors
 * @param {selectorParser.SyncProcessor<void>} callback
 * @return {string}
 */
function parseSelectors(selectors, callback) {
  return selectorParser(callback).processSync(selectors);
}

/**
 * @param {import('postcss').Rule} rule
 * @return {string}
 */
function unique(rule) {
  const selector = [...new Set(rule.selectors)];
  selector.sort();
  return selector.join();
}

/**
 * @type {import('postcss').PluginCreator<void>}
 * @return {import('postcss').Plugin}
 */
function pluginCreator() {
  return {
    postcssPlugin: 'postcss-unique-selectors',
    OnceExit(css) {
      css.walkRules((nodes) => {
        /** @type {string[]} */
        let comments = [];
        /** @type {selectorParser.SyncProcessor<void>} */
        const removeAndSaveComments = (selNode) => {
          selNode.walk((sel) => {
            if (sel.type === 'comment') {
              comments.push(sel.value);
              sel.remove();
              return;
            } else {
              return;
            }
          });
        };
        if (nodes.raws.selector && nodes.raws.selector.raw) {
          parseSelectors(nodes.raws.selector.raw, removeAndSaveComments);
          nodes.raws.selector.raw = unique(nodes);
        }
        nodes.selector = parseSelectors(nodes.selector, removeAndSaveComments);
        nodes.selector = unique(nodes);
        nodes.selectors = nodes.selectors.concat(comments);
      });
    },
  };
}

pluginCreator.postcss = true;
module.exports = pluginCreator;