Skip to content

Commit 4c1b02e

Browse files
committed
Add JSDoc based types
1 parent 4b4e243 commit 4c1b02e

22 files changed

+654
-209
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,33 @@
1+
/**
2+
* @typedef {import('unist').Node} Node
3+
*/
4+
15
import {any} from './lib/any.js'
26
import {parse} from './lib/parse.js'
37

8+
/**
9+
* @param {string} selector
10+
* @param {Node} [node]
11+
* @returns {boolean}
12+
*/
413
export function matches(selector, node) {
514
return Boolean(any(parse(selector), node, {one: true, shallow: true, any})[0])
615
}
716

17+
/**
18+
* @param {string} selector
19+
* @param {Node} [node]
20+
* @returns {Node|null}
21+
*/
822
export function select(selector, node) {
923
return any(parse(selector), node, {one: true, any})[0] || null
1024
}
1125

26+
/**
27+
* @param {string} selector
28+
* @param {Node} [node]
29+
* @returns {Array.<Node>}
30+
*/
1231
export function selectAll(selector, node) {
1332
return any(parse(selector), node, {any})
1433
}

lib/any.js

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,43 @@
1+
/**
2+
* @typedef {import('./types.js').Selector} Selector
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').RulePseudo} RulePseudo
7+
* @typedef {import('./types.js').Query} Query
8+
* @typedef {import('./types.js').Node} Node
9+
* @typedef {import('./types.js').Parent} Parent
10+
* @typedef {import('./types.js').SelectIterator} SelectIterator
11+
* @typedef {import('./types.js').SelectState} SelectState
12+
*/
13+
114
import {zwitch} from 'zwitch'
15+
import {nest} from './nest.js'
216
import {pseudo} from './pseudo.js'
317
import {test} from './test.js'
4-
import {nest} from './nest.js'
18+
import {root} from './util.js'
519

620
var type = zwitch('type', {
721
unknown: unknownType,
822
invalid: invalidType,
923
handlers: {selectors, ruleSet, rule}
1024
})
1125

26+
/**
27+
* @param {Selectors|RuleSet|Rule} query
28+
* @param {Node} node
29+
* @param {SelectState} state
30+
*/
1231
export function any(query, node, state) {
32+
// @ts-ignore zwitch types are off.
1333
return query && node ? type(query, node, state) : []
1434
}
1535

36+
/**
37+
* @param {Selectors} query
38+
* @param {Node} node
39+
* @param {SelectState} state
40+
*/
1641
function selectors(query, node, state) {
1742
var collect = collector(state.one)
1843
var index = -1
@@ -24,10 +49,20 @@ function selectors(query, node, state) {
2449
return collect.result
2550
}
2651

52+
/**
53+
* @param {RuleSet} query
54+
* @param {Node} node
55+
* @param {SelectState} state
56+
*/
2757
function ruleSet(query, node, state) {
2858
return rule(query.rule, node, state)
2959
}
3060

61+
/**
62+
* @param {Rule} query
63+
* @param {Node} tree
64+
* @param {SelectState} state
65+
*/
3166
function rule(query, tree, state) {
3267
var collect = collector(state.one)
3368

@@ -41,7 +76,8 @@ function rule(query, tree, state) {
4176
0,
4277
null,
4378
configure(query, {
44-
scopeNodes: tree.type === 'root' ? tree.children : [tree],
79+
scopeNodes: root(tree) ? tree.children : [tree],
80+
index: false,
4581
iterator,
4682
one: state.one,
4783
shallow: state.shallow,
@@ -51,9 +87,10 @@ function rule(query, tree, state) {
5187

5288
return collect.result
5389

90+
/** @type {SelectIterator} */
5491
function iterator(query, node, index, parent, state) {
5592
if (test(query, node, index, parent, state)) {
56-
if (query.rule) {
93+
if ('rule' in query) {
5794
nest(query.rule, node, index, parent, configure(query.rule, state))
5895
} else {
5996
collect(node)
@@ -63,6 +100,12 @@ function rule(query, tree, state) {
63100
}
64101
}
65102

103+
/**
104+
* @template {SelectState} S
105+
* @param {Rule} query
106+
* @param {S} state
107+
* @returns {S}
108+
*/
66109
function configure(query, state) {
67110
var pseudos = query.pseudos || []
68111
var index = -1
@@ -78,7 +121,10 @@ function configure(query, state) {
78121
}
79122

80123
// Shouldn’t be invoked, all data is handled.
81-
/* c8 ignore next 3 */
124+
/* c8 ignore next 6 */
125+
/**
126+
* @param {{[x: string]: unknown, type: string}} query
127+
*/
82128
function unknownType(query) {
83129
throw new Error('Unknown type `' + query.type + '`')
84130
}
@@ -89,15 +135,24 @@ function invalidType() {
89135
throw new Error('Invalid type')
90136
}
91137

138+
/**
139+
* @param {boolean} one
140+
*/
92141
function collector(one) {
142+
/** @type {Array.<Node>} */
93143
var result = []
144+
/** @type {boolean} */
94145
var found
95146

96147
collect.result = result
97148

98149
return collect
99150

100-
/* Append nodes to array, filtering out duplicates. */
151+
/**
152+
* Append nodes to array, filtering out duplicates.
153+
*
154+
* @param {Node|Array.<Node>} node
155+
*/
101156
function collect(node) {
102157
var index = -1
103158

@@ -110,6 +165,9 @@ function collector(one) {
110165
}
111166
}
112167

168+
/**
169+
* @param {Node} node
170+
*/
113171
function collectOne(node) {
114172
if (one) {
115173
/* Shouldn’t happen, safeguards performance problems. */

lib/attribute.js

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
/**
2+
* @typedef {import('./types.js').Rule} Rule
3+
* @typedef {import('./types.js').RuleAttr} RuleAttr
4+
* @typedef {import('./types.js').Node} Node
5+
*/
6+
17
import {zwitch} from 'zwitch'
28

39
var handle = zwitch('operator', {
@@ -12,47 +18,69 @@ var handle = zwitch('operator', {
1218
}
1319
})
1420

21+
/**
22+
* @param {Rule} query
23+
* @param {Node} node
24+
*/
1525
export function attribute(query, node) {
16-
var attrs = query.attrs
1726
var index = -1
1827

19-
while (++index < attrs.length) {
20-
if (!handle(attrs[index], node)) return false
28+
while (++index < query.attrs.length) {
29+
if (!handle(query.attrs[index], node)) return false
2130
}
2231

2332
return true
2433
}
2534

26-
// [attr]
35+
/**
36+
* `[attr]`
37+
*
38+
* @param {RuleAttr} query
39+
* @param {Node} node
40+
*/
2741
function exists(query, node) {
2842
return node[query.name] !== null && node[query.name] !== undefined
2943
}
3044

31-
// [attr=value]
45+
/**
46+
* `[attr=value]`
47+
*
48+
* @param {RuleAttr} query
49+
* @param {Node} node
50+
*/
3251
function exact(query, node) {
3352
return exists(query, node) && String(node[query.name]) === query.value
3453
}
3554

36-
// [attr~=value]
55+
/**
56+
* `[attr~=value]`
57+
*
58+
* @param {RuleAttr} query
59+
* @param {Node} node
60+
*/
3761
function containsArray(query, node) {
3862
var value = node[query.name]
3963

4064
if (value === null || value === undefined) return false
4165

4266
// If this is an array, and the query is contained in it, return true.
43-
if (
44-
typeof value === 'object' &&
45-
'length' in value &&
46-
value.includes(query.value)
47-
) {
67+
// Coverage comment in place because TS turns `Array.isArray(unknown)`
68+
// into `Array.<any>` instead of `Array.<unknown>`.
69+
// type-coverage:ignore-next-line
70+
if (Array.isArray(value) && value.includes(query.value)) {
4871
return true
4972
}
5073

5174
// For all other values, return whether this is an exact match.
5275
return String(value) === query.value
5376
}
5477

55-
// [attr^=value]
78+
/**
79+
* `[attr^=value]`
80+
*
81+
* @param {RuleAttr} query
82+
* @param {Node} node
83+
*/
5684
function begins(query, node) {
5785
var value = node[query.name]
5886

@@ -62,7 +90,12 @@ function begins(query, node) {
6290
)
6391
}
6492

65-
// [attr$=value]
93+
/**
94+
* `[attr$=value]`
95+
*
96+
* @param {RuleAttr} query
97+
* @param {Node} node
98+
*/
6699
function ends(query, node) {
67100
var value = node[query.name]
68101

@@ -72,14 +105,22 @@ function ends(query, node) {
72105
)
73106
}
74107

75-
// [attr*=value]
108+
/**
109+
* `[attr*=value]`
110+
*
111+
* @param {RuleAttr} query
112+
* @param {Node} node
113+
*/
76114
function containsString(query, node) {
77115
var value = node[query.name]
78116
return typeof value === 'string' && value.includes(query.value)
79117
}
80118

81119
// Shouldn’t be invoked, Parser throws an error instead.
82-
/* c8 ignore next 3 */
120+
/* c8 ignore next 6 */
121+
/**
122+
* @param {{[x: string]: unknown, type: string}} query
123+
*/
83124
function unknownOperator(query) {
84125
throw new Error('Unknown operator `' + query.operator + '`')
85126
}

lib/name.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
/**
2+
* @typedef {import('./types.js').Rule} Rule
3+
* @typedef {import('./types.js').Node} Node
4+
*/
5+
6+
/**
7+
* @param {Rule} query
8+
* @param {Node} node
9+
*/
110
export function name(query, node) {
211
return query.tagName === '*' || query.tagName === node.type
312
}

0 commit comments

Comments
 (0)