Skip to content

Commit 6b0fdb8

Browse files
committed
Add JSDoc based types
1 parent 465234f commit 6b0fdb8

19 files changed

+864
-163
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.DS_Store
2+
*.d.ts
23
*.log
34
coverage/
45
node_modules/

index.js

+24
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,40 @@
1+
/**
2+
* @typedef {import('./lib/types.js').Element} Element
3+
* @typedef {import('./lib/types.js').HastNode} HastNode
4+
* @typedef {import('./lib/types.js').Space} Space
5+
*/
6+
17
import {any} from './lib/any.js'
28
import {parse} from './lib/parse.js'
39

10+
/**
11+
* @param {string} selector
12+
* @param {HastNode} [node]
13+
* @param {Space} [space]
14+
* @returns {boolean}
15+
*/
416
export function matches(selector, node, space) {
517
return Boolean(
618
any(parse(selector), node, {space, one: true, shallow: true})[0]
719
)
820
}
921

22+
/**
23+
* @param {string} selector
24+
* @param {HastNode} [node]
25+
* @param {Space} [space]
26+
* @returns {Element|null}
27+
*/
1028
export function select(selector, node, space) {
1129
return any(parse(selector), node, {space, one: true})[0] || null
1230
}
1331

32+
/**
33+
* @param {string} selector
34+
* @param {HastNode} [node]
35+
* @param {Space} [space]
36+
* @returns {Array.<Element>}
37+
*/
1438
export function selectAll(selector, node, space) {
1539
return any(parse(selector), node, {space})
1640
}

lib/any.js

+88-31
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
/**
2+
* @typedef {import('hast').Element} Element
3+
* @typedef {import('./types.js').Selectors} Selectors
4+
* @typedef {import('./types.js').Rule} Rule
5+
* @typedef {import('./types.js').RuleSet} RuleSet
6+
* @typedef {import('./types.js').HastNode} HastNode
7+
* @typedef {import('./types.js').SelectIterator} SelectIterator
8+
* @typedef {import('./types.js').SelectState} SelectState
9+
*/
10+
111
import {html, svg} from 'property-information'
212
import {zwitch} from 'zwitch'
313
import {enterState} from './enter-state.js'
@@ -11,27 +21,52 @@ var type = zwitch('type', {
1121
handlers: {selectors, ruleSet, rule}
1222
})
1323

24+
/**
25+
* @param {Selectors|RuleSet|Rule} query
26+
* @param {HastNode} node
27+
* @param {SelectState} state
28+
* @returns {Array.<Element>}
29+
*/
1430
export function any(query, node, state) {
31+
// @ts-ignore zwitch types are off.
1532
return query && node ? type(query, node, state) : []
1633
}
1734

35+
/**
36+
* @param {Selectors} query
37+
* @param {HastNode} node
38+
* @param {SelectState} state
39+
* @returns {Array.<Element>}
40+
*/
1841
function selectors(query, node, state) {
19-
var collect = collector(state.one)
42+
var collector = new Collector(state.one)
2043
var index = -1
2144

2245
while (++index < query.selectors.length) {
23-
collect(ruleSet(query.selectors[index], node, state))
46+
collector.collectAll(ruleSet(query.selectors[index], node, state))
2447
}
2548

26-
return collect.result
49+
return collector.result
2750
}
2851

52+
/**
53+
* @param {RuleSet} query
54+
* @param {HastNode} node
55+
* @param {SelectState} state
56+
* @returns {Array.<Element>}
57+
*/
2958
function ruleSet(query, node, state) {
3059
return rule(query.rule, node, state)
3160
}
3261

62+
/**
63+
* @param {Rule} query
64+
* @param {HastNode} tree
65+
* @param {SelectState} state
66+
* @returns {Array.<Element>}
67+
*/
3368
function rule(query, tree, state) {
34-
var collect = collector(state.one)
69+
var collector = new Collector(state.one)
3570

3671
if (state.shallow && query.rule) {
3772
throw new Error('Expected selector without nesting')
@@ -47,30 +82,39 @@ function rule(query, tree, state) {
4782
language: null,
4883
direction: 'ltr',
4984
editableOrEditingHost: false,
85+
// @ts-ignore assume elements.
5086
scopeElements: tree.type === 'root' ? tree.children : [tree],
5187
iterator,
5288
one: state.one,
5389
shallow: state.shallow
5490
})
5591
)
5692

57-
return collect.result
93+
return collector.result
5894

95+
/** @type {SelectIterator} */
5996
function iterator(query, node, index, parent, state) {
6097
var exit = enterState(state, node)
6198

6299
if (test(query, node, index, parent, state)) {
63100
if (query.rule) {
64101
nest(query.rule, node, index, parent, configure(query.rule, state))
65102
} else {
66-
collect(node)
103+
// @ts-ignore `test` also asserts `node is Element`
104+
collector.collect(node)
67105
state.found = true
68106
}
69107
}
70108

71109
exit()
72110
}
73111

112+
/**
113+
* @template {SelectState} S
114+
* @param {Rule} query
115+
* @param {S} state
116+
* @returns {S}
117+
*/
74118
function configure(query, state) {
75119
var pseudos = query.pseudos || []
76120
var index = -1
@@ -87,7 +131,10 @@ function rule(query, tree, state) {
87131
}
88132

89133
// Shouldn’t be called, all data is handled.
90-
/* c8 ignore next 3 */
134+
/* c8 ignore next 6 */
135+
/**
136+
* @param {{[x: string]: unknown, type: string}} query
137+
*/
91138
function unknownType(query) {
92139
throw new Error('Unknown type `' + query.type + '`')
93140
}
@@ -98,35 +145,45 @@ function invalidType() {
98145
throw new Error('Invalid type')
99146
}
100147

101-
function collector(one) {
102-
var result = []
103-
var found
104-
105-
collect.result = result
106-
107-
return collect
148+
class Collector {
149+
/**
150+
* @param {boolean} one
151+
*/
152+
constructor(one) {
153+
/** @type {Array.<Element>} */
154+
this.result = []
155+
/** @type {boolean} */
156+
this.one = one
157+
/** @type {boolean} */
158+
this.found = false
159+
}
108160

109-
// Append elements to array, filtering out duplicates.
110-
function collect(source) {
161+
/**
162+
* Append nodes to array, filtering out duplicates.
163+
*
164+
* @param {Array.<Element>} elements
165+
*/
166+
collectAll(elements) {
111167
var index = -1
112168

113-
if ('length' in source) {
114-
while (++index < source.length) {
115-
collectOne(source[index])
116-
}
117-
} else {
118-
collectOne(source)
169+
while (++index < elements.length) {
170+
this.collect(elements[index])
119171
}
172+
}
120173

121-
function collectOne(element) {
122-
if (one) {
123-
// Shouldn’t happen, safeguards performance problems.
124-
/* c8 ignore next */
125-
if (found) throw new Error('Cannot collect multiple nodes')
126-
found = true
127-
}
128-
129-
if (!result.includes(element)) result.push(element)
174+
/**
175+
* Append one node.
176+
*
177+
* @param {Element} element
178+
*/
179+
collect(element) {
180+
if (this.one) {
181+
// Shouldn’t happen, safeguards performance problems.
182+
/* c8 ignore next */
183+
if (this.found) throw new Error('Cannot collect multiple nodes')
184+
this.found = true
130185
}
186+
187+
if (!this.result.includes(element)) this.result.push(element)
131188
}
132189
}

0 commit comments

Comments
 (0)