-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
95 lines (87 loc) · 2.34 KB
/
index.js
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/* eslint-disable import/no-namespace */
import * as postcss from 'postcss';
import selectorParser from 'postcss-selector-parser';
import getSelectorAst from './lib/selector-ast';
import getCombinator from './lib/node/combinator';
import getTag from './lib/node/tag';
import getAttribute from './lib/node/attribute';
import getPseudo from './lib/node/pseudo';
import PassthroughContainer from './lib/passthrough-container';
/**
* @typedef {(
* selectors: selectorParser.Container|selectorParser.Root,
* ast: postcss.Root|postcss.ChildNode|PassthroughContainer
* ) => (postcss.Root|postcss.ChildNode|PassthroughContainer)[]} ProcessSelectors
*/
/**
* @type {ProcessSelectors}
*/
function processSelectors(selectors, ast) {
const nodes = selectors
.map((rootSelector) => {
if (!selectorParser.isSelector(rootSelector)) {
return [];
}
return rootSelector.reduce(
(astContainer, selector) => {
return astContainer
.map((node) => {
if (
node instanceof postcss.Root ||
node instanceof PassthroughContainer
) {
switch (selector.type) {
case 'tag':
case 'universal':
return getTag(node, selector);
default:
return [];
}
}
switch (selector.type) {
case 'combinator':
return getCombinator(node, selector);
case 'attribute':
return getAttribute(node, selector);
case 'pseudo':
return getPseudo(
node,
selector,
processSelectors
);
default:
return [];
}
})
.reduce(
(
/** @type {(postcss.ChildNode|PassthroughContainer)[]}*/ array,
result
) => [...array, ...result],
[]
)
.filter((result) => result !== null);
},
[ast]
);
})
.reduce((array, result) => [...array, ...result], []);
const uniqueNodes = [...new Set(nodes)];
return uniqueNodes;
}
/**
* Queries PostCSS with CSS selector.
*
* @param {string} query CSS selector.
* @param {postcss.Root} ast PostCSS AST.
*/
export default async function (query, ast) {
const selectorAst = await getSelectorAst(query);
const result = [];
for (const node of processSelectors(selectorAst, ast)) {
if (!(node instanceof PassthroughContainer)) {
result.push(node);
}
}
return result;
}