@@ -11,59 +11,84 @@ import {zwitch} from 'zwitch'
1111import { nest } from './nest.js'
1212import { pseudo } from './pseudo.js'
1313import { test } from './test.js'
14- import { root } from './util.js'
1514
15+ /** @type {(query: Selectors | RuleSet | Rule, node: Node, state: SelectState) => Array<Node> } */
1616const 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 */
3034export 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 */
4050function 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 */
5674function 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 */
6590function 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 */
132173function 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 */
138183function 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}
0 commit comments