Skip to content

Commit beca7d5

Browse files
committed
Fix support for parent-sensitive pseudos
Previously, `:any`, `:matches`, and `:not` did not support selectors sensitive to their parent. This is now fixed. Related-to syntax-tree/hast-util-select#5.
1 parent 96ea63a commit beca7d5

File tree

7 files changed

+81
-22
lines changed

7 files changed

+81
-22
lines changed

lib/any.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
/**
2-
* @typedef {import('./types.js').Selector} Selector
32
* @typedef {import('./types.js').Selectors} Selectors
43
* @typedef {import('./types.js').Rule} Rule
54
* @typedef {import('./types.js').RuleSet} RuleSet
6-
* @typedef {import('./types.js').RulePseudo} RulePseudo
7-
* @typedef {import('./types.js').Query} Query
85
* @typedef {import('./types.js').Node} Node
9-
* @typedef {import('./types.js').Parent} Parent
106
* @typedef {import('./types.js').SelectIterator} SelectIterator
117
* @typedef {import('./types.js').SelectState} SelectState
128
*/
@@ -79,12 +75,17 @@ function rule(query, tree, state) {
7975
0,
8076
null,
8177
configure(query, {
82-
scopeNodes: root(tree) ? tree.children : [tree],
83-
index: false,
78+
any: state.any,
8479
iterator,
80+
scopeNodes: root(tree) ? tree.children : [tree],
8581
one: state.one,
8682
shallow: state.shallow,
87-
any: state.any
83+
index: false,
84+
found: false,
85+
typeIndex: state.typeIndex,
86+
nodeIndex: state.nodeIndex,
87+
typeCount: state.typeCount,
88+
nodeCount: state.nodeCount
8889
})
8990
)
9091

lib/nest.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/**
22
* @typedef {import('./types.js').Rule} Rule
3-
* @typedef {import('./types.js').Query} Query
43
* @typedef {import('./types.js').Node} Node
54
* @typedef {import('./types.js').Parent} Parent
65
* @typedef {import('./types.js').SelectState} SelectState

lib/pseudo.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,13 @@ const handle = zwitch('name', {
6161
})
6262

6363
pseudo.needsIndex = [
64+
'any',
6465
'first-child',
6566
'first-of-type',
6667
'last-child',
6768
'last-of-type',
69+
'matches',
70+
'not',
6871
'nth-child',
6972
'nth-last-child',
7073
'nth-of-type',
@@ -104,8 +107,8 @@ function matches(query, node, _1, _2, state) {
104107
const shallow = state.shallow
105108
const one = state.one
106109

110+
state.shallow = false
107111
state.one = true
108-
state.shallow = true
109112

110113
const result = state.any(query.value, node, state)[0] === node
111114

lib/types.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,20 @@
3131
*
3232
* @typedef {Object} SelectState
3333
* @property {(query: Selectors|RuleSet|Rule, node: Node|undefined, state: SelectState) => Node[]} any
34-
* @property {Array.<Node>} [scopeNodes]
3534
* @property {SelectIterator|null|undefined} [iterator]
35+
* @property {Array<Node>} [scopeNodes]
3636
* @property {boolean} [one=false]
3737
* @property {boolean} [shallow=false]
3838
* @property {boolean} [index=false]
3939
* @property {boolean} [found=false]
40-
* @property {number} [typeIndex] Track siblings
41-
* @property {number} [nodeIndex] Track siblings
42-
* @property {number} [typeCount] Track siblings
43-
* @property {number} [nodeCount] Track siblings
40+
* @property {number} [typeIndex]
41+
* Track siblings: this current node has `n` nodes with its type before it.
42+
* @property {number} [nodeIndex]
43+
* Track siblings: this current node has `n` nodes before it.
44+
* @property {number} [typeCount]
45+
* Track siblings: there are `n` siblings with this node’s type.
46+
* @property {number} [nodeCount]
47+
* Track siblings: there are `n` siblings.
4448
*/
4549

4650
/**

lib/util.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
/**
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
82
* @typedef {import('./types.js').Node} Node
93
* @typedef {import('./types.js').Parent} Parent
10-
* @typedef {import('./types.js').SelectIterator} SelectIterator
11-
* @typedef {import('./types.js').SelectState} SelectState
124
*/
135

146
/**

test/select-all.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,5 +740,35 @@ test('select.selectAll()', (t) => {
740740
st.end()
741741
})
742742

743+
t.test(':any', (t) => {
744+
t.deepEqual(
745+
selectAll('y:any(:first-child)', u('x', [u('y', 'a'), u('y', 'b')])),
746+
[u('y', 'a')],
747+
'should support parent-sensitive `:any`'
748+
)
749+
750+
t.end()
751+
})
752+
753+
t.test(':matches', (t) => {
754+
t.deepEqual(
755+
selectAll('y:matches(:first-child)', u('x', [u('y', 'a'), u('y', 'b')])),
756+
[u('y', 'a')],
757+
'should support parent-sensitive `:matches`'
758+
)
759+
760+
t.end()
761+
})
762+
763+
t.test(':not', (t) => {
764+
t.deepEqual(
765+
selectAll('y:not(:first-child)', u('x', [u('y', 'a'), u('y', 'b')])),
766+
[u('y', 'b')],
767+
'should support parent-sensitive `:not`'
768+
)
769+
770+
t.end()
771+
})
772+
743773
t.end()
744774
})

test/select.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,5 +706,35 @@ test('select.select()', (t) => {
706706
st.end()
707707
})
708708

709+
t.test(':any', (t) => {
710+
t.deepEqual(
711+
select('y:any(:first-child)', u('x', [u('y', 'a'), u('y', 'b')])),
712+
u('y', 'a'),
713+
'should support parent-sensitive `:any`'
714+
)
715+
716+
t.end()
717+
})
718+
719+
t.test(':matches', (t) => {
720+
t.deepEqual(
721+
select('y:matches(:first-child)', u('x', [u('y', 'a'), u('y', 'b')])),
722+
u('y', 'a'),
723+
'should support parent-sensitive `:matches`'
724+
)
725+
726+
t.end()
727+
})
728+
729+
t.test(':not', (t) => {
730+
t.deepEqual(
731+
select('y:not(:first-child)', u('x', [u('y', 'a'), u('y', 'b')])),
732+
u('y', 'b'),
733+
'should support parent-sensitive `:not`'
734+
)
735+
736+
t.end()
737+
})
738+
709739
t.end()
710740
})

0 commit comments

Comments
 (0)