-
-
Notifications
You must be signed in to change notification settings - Fork 10
/
index.js
109 lines (103 loc) · 2.88 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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/**
* @typedef {import('unist').Position} Position
* @typedef {import('unist').Node} Node
* @typedef {import('./lib/types.js').SelectState} SelectState
*/
/**
* @typedef {Record<string, unknown> & {type: string, position?: Position | undefined}} NodeLike
*/
import {parse} from './lib/parse.js'
import {parent} from './lib/util.js'
import {walk} from './lib/walk.js'
/**
* Check that the given `node` matches `selector`.
*
* This only checks the node itself, not the surrounding tree.
* Thus, nesting in selectors is not supported (`paragraph strong`,
* `paragraph > strong`), neither are selectors like `:first-child`, etc.
* This only checks that the given node matches the selector.
*
* @param {string} selector
* CSS selector, such as (`heading`, `link, linkReference`).
* @param {Node | NodeLike | null | undefined} [node]
* Node that might match `selector`.
* @returns {boolean}
* Whether `node` matches `selector`.
*/
export function matches(selector, node) {
const state = createState(selector, node)
state.one = true
state.shallow = true
walk(state, node || undefined)
return state.results.length > 0
}
/**
* Select the first node that matches `selector` in the given `tree`.
*
* Searches the tree in *preorder*.
*
* @param {string} selector
* CSS selector, such as (`heading`, `link, linkReference`).
* @param {Node | NodeLike | null | undefined} [tree]
* Tree to search.
* @returns {Node | undefined}
* First node in `tree` that matches `selector` or `null` if nothing is
* found.
*
* This could be `tree` itself.
*/
export function select(selector, tree) {
const state = createState(selector, tree)
state.one = true
walk(state, tree || undefined)
return state.results[0]
}
/**
* Select all nodes that match `selector` in the given `tree`.
*
* Searches the tree in *preorder*.
*
* @param {string} selector
* CSS selector, such as (`heading`, `link, linkReference`).
* @param {Node | NodeLike | null | undefined} [tree]
* Tree to search.
* @returns {Array<Node>}
* Nodes in `tree` that match `selector`.
*
* This could include `tree` itself.
*/
export function selectAll(selector, tree) {
const state = createState(selector, tree)
walk(state, tree || undefined)
return state.results
}
/**
* @param {string} selector
* Selector to parse.
* @param {Node | null | undefined} tree
* Tree to search.
* @returns {SelectState}
* State.
*/
function createState(selector, tree) {
return {
// State of the query.
rootQuery: parse(selector),
results: [],
scopeNodes: tree
? parent(tree) &&
// Root in nlcst.
(tree.type === 'RootNode' || tree.type === 'root')
? tree.children
: [tree]
: [],
one: false,
shallow: false,
found: false,
// State in the tree.
typeIndex: undefined,
nodeIndex: undefined,
typeCount: undefined,
nodeCount: undefined
}
}