Skip to content

Commit 191aa36

Browse files
committed
Refactor internal types
1 parent 6ee499e commit 191aa36

File tree

9 files changed

+295
-177
lines changed

9 files changed

+295
-177
lines changed

index.js

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* @typedef {import('./lib/types.js').Space} Space
55
*/
66

7+
import {html, svg} from 'property-information'
78
import {any} from './lib/any.js'
89
import {parse} from './lib/parse.js'
910

@@ -25,13 +26,10 @@ import {parse} from './lib/parse.js'
2526
* Whether `node` matches `selector`.
2627
*/
2728
export function matches(selector, node, space) {
28-
return Boolean(
29-
any(parse(selector), node || undefined, {
30-
space: space || undefined,
31-
one: true,
32-
shallow: true
33-
})[0]
34-
)
29+
const state = createState(node, space)
30+
state.one = true
31+
state.shallow = true
32+
return Boolean(any(parse(selector), node || undefined, state)[0])
3533
}
3634

3735
/**
@@ -44,19 +42,16 @@ export function matches(selector, node, space) {
4442
* Tree to search.
4543
* @param {Space | null | undefined} [space='html']
4644
* Name of namespace (`'svg'` or `'html'`).
47-
* @returns {Element|null}
45+
* @returns {Element | null}
4846
* First element in `tree` that matches `selector` or `null` if nothing is
4947
* found.
5048
* This could be `tree` itself.
5149
*/
5250
export function select(selector, tree, space) {
51+
const state = createState(tree, space)
52+
state.one = true
5353
// To do in major: return `undefined` instead.
54-
return (
55-
any(parse(selector), tree || undefined, {
56-
space: space || undefined,
57-
one: true
58-
})[0] || null
59-
)
54+
return any(parse(selector), tree || undefined, state)[0] || null
6055
}
6156

6257
/**
@@ -74,5 +69,33 @@ export function select(selector, tree, space) {
7469
* This could include `tree` itself.
7570
*/
7671
export function selectAll(selector, tree, space) {
77-
return any(parse(selector), tree || undefined, {space: space || undefined})
72+
const state = createState(tree, space)
73+
return any(parse(selector), tree || undefined, state)
74+
}
75+
76+
/**
77+
* @param {Node | null | undefined} [tree]
78+
* Tree to search.
79+
* @param {Space | null | undefined} [space='html']
80+
* Name of namespace (`'svg'` or `'html'`).
81+
* @returns {import('./lib/types.js').SelectState} SelectState
82+
*/
83+
function createState(tree, space) {
84+
return {
85+
// @ts-expect-error assume elements.
86+
scopeElements: tree ? (tree.type === 'root' ? tree.children : [tree]) : [],
87+
iterator: undefined,
88+
one: false,
89+
shallow: false,
90+
index: false,
91+
found: false,
92+
schema: space === 'svg' ? svg : html,
93+
language: undefined,
94+
direction: 'ltr',
95+
editableOrEditingHost: false,
96+
typeIndex: undefined,
97+
elementIndex: undefined,
98+
typeCount: undefined,
99+
elementCount: undefined
100+
}
78101
}

lib/any.js

Lines changed: 78 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -8,62 +8,86 @@
88
* @typedef {import('./types.js').SelectState} SelectState
99
*/
1010

11-
import {html, svg} from 'property-information'
1211
import {zwitch} from 'zwitch'
1312
import {enterState} from './enter-state.js'
1413
import {nest} from './nest.js'
1514
import {pseudo} from './pseudo.js'
1615
import {test} from './test.js'
1716

18-
/** @type {(query: Selectors|RuleSet|Rule, element: Node, state: SelectState) => Array<Element>} */
17+
/** @type {(query: Selectors | RuleSet | Rule, element: Node, state: SelectState) => Array<Element>} */
1918
const type = zwitch('type', {
2019
unknown: unknownType,
2120
invalid: invalidType,
2221
handlers: {selectors, ruleSet, rule}
2322
})
2423

2524
/**
26-
* @param {Selectors|RuleSet|Rule} query
27-
* @param {Node|undefined} node
25+
* Handle an optional query and node.
26+
*
27+
* @param {Selectors | RuleSet | Rule | undefined} query
28+
* Thing to find.
29+
* @param {Node | undefined} node
30+
* Tree.
2831
* @param {SelectState} state
32+
* State.
2933
* @returns {Array<Element>}
34+
* Results.
3035
*/
3136
export function any(query, node, state) {
3237
return query && node ? type(query, node, state) : []
3338
}
3439

3540
/**
41+
* Handle selectors.
42+
*
3643
* @param {Selectors} query
44+
* Multiple selectors.
3745
* @param {Node} node
46+
* Tree.
3847
* @param {SelectState} state
48+
* State.
3949
* @returns {Array<Element>}
50+
* Results.
4051
*/
4152
function selectors(query, node, state) {
4253
const collector = new Collector(state.one)
4354
let index = -1
4455

4556
while (++index < query.selectors.length) {
46-
collector.collectAll(ruleSet(query.selectors[index], node, state))
57+
const set = query.selectors[index]
58+
collector.collectAll(rule(set.rule, node, state))
4759
}
4860

4961
return collector.result
5062
}
5163

5264
/**
65+
* Handle a selector.
66+
*
5367
* @param {RuleSet} query
68+
* One selector.
5469
* @param {Node} node
70+
* Tree.
5571
* @param {SelectState} state
72+
* State.
5673
* @returns {Array<Element>}
74+
* Results.
5775
*/
5876
function ruleSet(query, node, state) {
5977
return rule(query.rule, node, state)
6078
}
6179

6280
/**
81+
* Handle a rule.
82+
*
6383
* @param {Rule} query
84+
* One rule.
6485
* @param {Node} tree
86+
* Tree.
6587
* @param {SelectState} state
88+
* State.
6689
* @returns {Array<Element>}
90+
* Results.
6791
*/
6892
function rule(query, tree, state) {
6993
const collector = new Collector(state.one)
@@ -72,30 +96,11 @@ function rule(query, tree, state) {
7296
throw new Error('Expected selector without nesting')
7397
}
7498

75-
nest(
76-
query,
77-
tree,
78-
0,
79-
undefined,
80-
configure(query, {
81-
// @ts-expect-error assume elements.
82-
scopeElements: tree.type === 'root' ? tree.children : [tree],
83-
iterator,
84-
one: state.one,
85-
shallow: state.shallow,
86-
index: false,
87-
found: false,
88-
space: state.space,
89-
schema: state.space === 'svg' ? svg : html,
90-
language: undefined,
91-
direction: 'ltr',
92-
editableOrEditingHost: false,
93-
typeIndex: state.typeIndex,
94-
elementIndex: state.elementIndex,
95-
typeCount: state.typeCount,
96-
elementCount: state.elementCount
97-
})
98-
)
99+
nest(query, tree, 0, undefined, {
100+
...state,
101+
iterator,
102+
index: needsIndex(query)
103+
})
99104

100105
return collector.result
101106

@@ -105,7 +110,11 @@ function rule(query, tree, state) {
105110

106111
if (test(query, node, index, parent, state)) {
107112
if (query.rule) {
108-
nest(query.rule, node, index, parent, configure(query.rule, state))
113+
nest(query.rule, node, index, parent, {
114+
...state,
115+
iterator,
116+
index: needsIndex(query.rule)
117+
})
109118
} else {
110119
// @ts-expect-error `test` also asserts `node is Element`
111120
collector.collect(node)
@@ -115,26 +124,25 @@ function rule(query, tree, state) {
115124

116125
exit()
117126
}
127+
}
118128

119-
/**
120-
* @template {SelectState} S
121-
* @param {Rule} query
122-
* @param {S} state
123-
* @returns {S}
124-
*/
125-
function configure(query, state) {
126-
const pseudos = query.pseudos || []
127-
let index = -1
129+
/**
130+
* Check if indexing is needed.
131+
*
132+
* @param {Rule} query
133+
* @returns {boolean}
134+
*/
135+
function needsIndex(query) {
136+
const pseudos = query.pseudos || []
137+
let index = -1
128138

129-
while (++index < pseudos.length) {
130-
if (pseudo.needsIndex.includes(pseudos[index].name)) {
131-
state.index = true
132-
break
133-
}
139+
while (++index < pseudos.length) {
140+
if (pseudo.needsIndex.includes(pseudos[index].name)) {
141+
return true
134142
}
135-
136-
return state
137143
}
144+
145+
return false
138146
}
139147

140148
// Shouldn’t be called, all data is handled.
@@ -154,21 +162,38 @@ function invalidType() {
154162
throw new Error('Invalid type')
155163
}
156164

165+
/**
166+
* Collect elements.
167+
*/
157168
class Collector {
158169
/**
159-
* @param {boolean|undefined} [one]
170+
* @param {boolean | undefined} one
160171
*/
161172
constructor(one) {
162-
/** @type {Array<Element>} */
173+
/**
174+
* Found elements.
175+
*
176+
* @type {Array<Element>}
177+
*/
163178
this.result = []
164-
/** @type {boolean|undefined} */
165-
this.one = one
166-
/** @type {boolean} */
179+
180+
/**
181+
* Whether we’re looking for one result.
182+
*
183+
* @type {boolean}
184+
*/
185+
this.one = one || false
186+
187+
/**
188+
* Whether we’ve found something.
189+
*
190+
* @type {boolean}
191+
*/
167192
this.found = false
168193
}
169194

170195
/**
171-
* Append nodes to array, filtering out duplicates.
196+
* Add multiple elements.
172197
*
173198
* @param {Array<Element>} elements
174199
*/
@@ -181,7 +206,7 @@ class Collector {
181206
}
182207

183208
/**
184-
* Append one node.
209+
* Add one element.
185210
*
186211
* @param {Element} element
187212
*/

lib/attribute.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ function spaceSeparatedList(query, element, info) {
8787
const value = element.properties && element.properties[info.property]
8888

8989
return (
90-
// If this is a comma-separated list, and the query is contained in it, return
90+
// If this is a space-separated list, and the query is contained in it, return
9191
// true.
9292
(!info.commaSeparated &&
9393
value &&

0 commit comments

Comments
 (0)