Skip to content

Commit dc787fb

Browse files
committed
Refactor internal types
1 parent 5e05a61 commit dc787fb

File tree

6 files changed

+226
-127
lines changed

6 files changed

+226
-127
lines changed

lib/any.js

Lines changed: 109 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -11,59 +11,84 @@ import {zwitch} from 'zwitch'
1111
import {nest} from './nest.js'
1212
import {pseudo} from './pseudo.js'
1313
import {test} from './test.js'
14-
import {root} from './util.js'
1514

15+
/** @type {(query: Selectors | RuleSet | Rule, node: Node, state: SelectState) => Array<Node>} */
1616
const type = zwitch('type', {
17-
// @ts-expect-error: hush.
1817
unknown: unknownType,
1918
invalid: invalidType,
20-
// @ts-expect-error: hush.
2119
handlers: {selectors, ruleSet, rule}
2220
})
2321

2422
/**
25-
* @param {Selectors | RuleSet | Rule} query
23+
* Handle an optional query and node.
24+
*
25+
* @param {Selectors | RuleSet | Rule | undefined} query
26+
* Thing to find.
2627
* @param {Node | undefined} node
28+
* Tree.
2729
* @param {SelectState} state
30+
* State.
2831
* @returns {Array<Node>}
32+
* Results.
2933
*/
3034
export function any(query, node, state) {
31-
// @ts-expect-error: fine.
3235
return query && node ? type(query, node, state) : []
3336
}
3437

3538
/**
39+
* Handle selectors.
40+
*
3641
* @param {Selectors} query
42+
* Multiple selectors.
3743
* @param {Node} node
44+
* Tree.
3845
* @param {SelectState} state
46+
* State.
47+
* @returns {Array<Node>}
48+
* Results.
3949
*/
4050
function selectors(query, node, state) {
41-
const collect = collector(state.one)
51+
const collector = new Collector(state.one)
4252
let index = -1
4353

4454
while (++index < query.selectors.length) {
45-
collect(ruleSet(query.selectors[index], node, state))
55+
const set = query.selectors[index]
56+
collector.collectAll(rule(set.rule, node, state))
4657
}
4758

48-
return collect.result
59+
return collector.result
4960
}
5061

5162
/**
63+
* Handle a selector.
64+
*
5265
* @param {RuleSet} query
66+
* One selector.
5367
* @param {Node} node
68+
* Tree.
5469
* @param {SelectState} state
70+
* State.
71+
* @returns {Array<Node>}
72+
* Results.
5573
*/
5674
function ruleSet(query, node, state) {
5775
return rule(query.rule, node, state)
5876
}
5977

6078
/**
79+
* Handle a rule.
80+
*
6181
* @param {Rule} query
82+
* One rule.
6283
* @param {Node} tree
84+
* Tree.
6385
* @param {SelectState} state
86+
* State.
87+
* @returns {Array<Node>}
88+
* Results.
6489
*/
6590
function rule(query, tree, state) {
66-
const collect = collector(state.one)
91+
const collector = new Collector(state.one)
6792

6893
if (state.shallow && query.rule) {
6994
throw new Error('Expected selector without nesting')
@@ -75,35 +100,50 @@ function rule(query, tree, state) {
75100
0,
76101
undefined,
77102
configure(query, {
78-
any: state.any,
103+
...state,
79104
iterator,
80-
scopeNodes: root(tree) ? tree.children : [tree],
81-
one: state.one,
82-
shallow: state.shallow,
83-
index: false,
84-
found: false,
85-
typeIndex: state.typeIndex,
86-
nodeIndex: state.nodeIndex,
87-
typeCount: state.typeCount,
88-
nodeCount: state.nodeCount
105+
index: needsIndex(query)
89106
})
90107
)
91108

92-
return collect.result
109+
return collector.result
93110

94111
/** @type {SelectIterator} */
95112
function iterator(query, node, index, parent, state) {
96113
if (test(query, node, index, parent, state)) {
97114
if (query.rule) {
98-
nest(query.rule, node, index, parent, configure(query.rule, state))
115+
nest(query.rule, node, index, parent, {
116+
...state,
117+
iterator,
118+
index: needsIndex(query.rule)
119+
})
99120
} else {
100-
collect(node)
121+
collector.collect(node)
101122
state.found = true
102123
}
103124
}
104125
}
105126
}
106127

128+
/**
129+
* Check if indexing is needed.
130+
*
131+
* @param {Rule} query
132+
* @returns {boolean}
133+
*/
134+
function needsIndex(query) {
135+
const pseudos = query.pseudos || []
136+
let index = -1
137+
138+
while (++index < pseudos.length) {
139+
if (pseudo.needsIndex.includes(pseudos[index].name)) {
140+
return true
141+
}
142+
}
143+
144+
return false
145+
}
146+
107147
/**
108148
* @template {SelectState} S
109149
* @param {Rule} query
@@ -125,62 +165,81 @@ function configure(query, state) {
125165
}
126166

127167
// Shouldn’t be called, all data is handled.
128-
/* c8 ignore next 6 */
129168
/**
130-
* @param {{[x: string]: unknown, type: string}} query
169+
* @param {unknown} query
170+
* @returns {never}
131171
*/
172+
/* c8 ignore next 4 */
132173
function unknownType(query) {
174+
// @ts-expect-error: `type` guaranteed.
133175
throw new Error('Unknown type `' + query.type + '`')
134176
}
135177

136178
// Shouldn’t be called, parser gives correct data.
179+
/**
180+
* @returns {never}
181+
*/
137182
/* c8 ignore next 3 */
138183
function invalidType() {
139184
throw new Error('Invalid type')
140185
}
141186

142187
/**
143-
* @param {boolean | undefined} one
188+
* Collect nodes.
144189
*/
145-
function collector(one) {
146-
/** @type {Array<Node>} */
147-
const result = []
148-
/** @type {boolean} */
149-
let found
150-
151-
collect.result = result
152-
153-
return collect
190+
class Collector {
191+
/**
192+
* @param {boolean | undefined} one
193+
*/
194+
constructor(one) {
195+
/**
196+
* Found nodes.
197+
*
198+
* @type {Array<Node>}
199+
*/
200+
this.result = []
201+
202+
/**
203+
* Whether we’re looking for one result.
204+
*
205+
* @type {boolean}
206+
*/
207+
this.one = one || false
208+
209+
/**
210+
* Whether we’ve found something.
211+
*
212+
* @type {boolean}
213+
*/
214+
this.found = false
215+
}
154216

155217
/**
156-
* Append nodes to array, filtering out duplicates.
218+
* Add multiple nodes.
157219
*
158-
* @param {Node | Array<Node>} node
220+
* @param {Array<Node>} nodes
159221
*/
160-
function collect(node) {
222+
collectAll(nodes) {
161223
let index = -1
162224

163-
if ('length' in node) {
164-
while (++index < node.length) {
165-
collectOne(node[index])
166-
}
167-
} else {
168-
collectOne(node)
225+
while (++index < nodes.length) {
226+
this.collect(nodes[index])
169227
}
170228
}
171229

172230
/**
231+
* Add one node.
232+
*
173233
* @param {Node} node
174234
*/
175-
function collectOne(node) {
176-
if (one) {
177-
/* Shouldn’t happen, safeguards performance problems. */
235+
collect(node) {
236+
if (this.one) {
237+
// Shouldn’t happen, safeguards performance problems.
178238
/* c8 ignore next */
179-
if (found) throw new Error('Cannot collect multiple nodes')
180-
181-
found = true
239+
if (this.found) return
240+
this.found = true
182241
}
183242

184-
if (!result.includes(node)) result.push(node)
243+
if (!this.result.includes(node)) this.result.push(node)
185244
}
186245
}

lib/attribute.js

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,24 @@
66

77
import {zwitch} from 'zwitch'
88

9+
/** @type {(query: RuleAttr, node: Node) => boolean} */
910
const handle = zwitch('operator', {
10-
// @ts-expect-error: hush.
1111
unknown: unknownOperator,
1212
// @ts-expect-error: hush.
1313
invalid: exists,
1414
handlers: {
15-
// @ts-expect-error: hush.
1615
'=': exact,
17-
// @ts-expect-error: hush.
1816
'^=': begins,
19-
// @ts-expect-error: hush.
2017
'$=': ends,
21-
// @ts-expect-error: hush.
2218
'*=': containsString,
23-
// @ts-expect-error: hush.
2419
'~=': containsArray
2520
}
2621
})
2722

2823
/**
2924
* @param {Rule} query
3025
* @param {Node} node
26+
* @returns {boolean}
3127
*/
3228
export function attribute(query, node) {
3329
let index = -1
@@ -44,6 +40,7 @@ export function attribute(query, node) {
4440
*
4541
* @param {RuleAttr} query
4642
* @param {Node} node
43+
* @returns {boolean}
4744
*/
4845
function exists(query, node) {
4946
// @ts-expect-error: Looks like a record.
@@ -55,6 +52,7 @@ function exists(query, node) {
5552
*
5653
* @param {RuleAttr} query
5754
* @param {Node} node
55+
* @returns {boolean}
5856
*/
5957
function exact(query, node) {
6058
// @ts-expect-error: Looks like a record.
@@ -66,6 +64,7 @@ function exact(query, node) {
6664
*
6765
* @param {RuleAttr} query
6866
* @param {Node} node
67+
* @returns {boolean}
6968
*/
7069
function containsArray(query, node) {
7170
/** @type {unknown} */
@@ -91,16 +90,17 @@ function containsArray(query, node) {
9190
*
9291
* @param {RuleAttr} query
9392
* @param {Node} node
93+
* @returns {boolean}
9494
*/
9595
function begins(query, node) {
9696
/** @type {unknown} */
9797
// @ts-expect-error: Looks like a record.
9898
const value = node[query.name]
9999

100-
return (
100+
return Boolean(
101101
query.value &&
102-
typeof value === 'string' &&
103-
value.slice(0, query.value.length) === query.value
102+
typeof value === 'string' &&
103+
value.slice(0, query.value.length) === query.value
104104
)
105105
}
106106

@@ -109,16 +109,17 @@ function begins(query, node) {
109109
*
110110
* @param {RuleAttr} query
111111
* @param {Node} node
112+
* @returns {boolean}
112113
*/
113114
function ends(query, node) {
114115
/** @type {unknown} */
115116
// @ts-expect-error: Looks like a record.
116117
const value = node[query.name]
117118

118-
return (
119+
return Boolean(
119120
query.value &&
120-
typeof value === 'string' &&
121-
value.slice(-query.value.length) === query.value
121+
typeof value === 'string' &&
122+
value.slice(-query.value.length) === query.value
122123
)
123124
}
124125

@@ -127,19 +128,24 @@ function ends(query, node) {
127128
*
128129
* @param {RuleAttr} query
129130
* @param {Node} node
131+
* @returns {boolean}
130132
*/
131133
function containsString(query, node) {
132134
/** @type {unknown} */
133135
// @ts-expect-error: Looks like a record.
134136
const value = node[query.name]
135-
return query.value && typeof value === 'string' && value.includes(query.value)
137+
return Boolean(
138+
query.value && typeof value === 'string' && value.includes(query.value)
139+
)
136140
}
137141

138142
// Shouldn’t be called, parser throws an error instead.
139-
/* c8 ignore next 6 */
140143
/**
141-
* @param {{[x: string]: unknown, type: string}} query
144+
* @param {unknown} query
145+
* @returns {never}
142146
*/
147+
/* c8 ignore next 4 */
143148
function unknownOperator(query) {
149+
// @ts-expect-error: `operator` guaranteed.
144150
throw new Error('Unknown operator `' + query.operator + '`')
145151
}

0 commit comments

Comments
 (0)