Skip to content

Commit 804cc39

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. Closes GH-5.
1 parent 022ab8e commit 804cc39

File tree

7 files changed

+91
-19
lines changed

7 files changed

+91
-19
lines changed

lib/any.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,22 @@ function rule(query, tree, state) {
7878
0,
7979
null,
8080
configure(query, {
81-
schema: state.space === 'svg' ? svg : html,
82-
language: undefined,
83-
direction: 'ltr',
84-
editableOrEditingHost: false,
8581
// @ts-expect-error assume elements.
8682
scopeElements: tree.type === 'root' ? tree.children : [tree],
8783
iterator,
8884
one: state.one,
89-
shallow: state.shallow
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
9097
})
9198
)
9299

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').Node} Node
43
* @typedef {import('./types.js').Element} Element
54
* @typedef {import('./types.js').Parent} Parent
65
* @typedef {import('./types.js').SelectState} SelectState

lib/pseudo.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,13 @@ const handle = zwitch('name', {
5656
})
5757

5858
pseudo.needsIndex = [
59+
'any',
5960
'first-child',
6061
'first-of-type',
6162
'last-child',
6263
'last-of-type',
64+
'matches',
65+
'not',
6366
'nth-child',
6467
'nth-last-child',
6568
'nth-of-type',
@@ -90,16 +93,16 @@ export function pseudo(query, element, index, parent, state) {
9093
/**
9194
* @param {RulePseudoSelector} query
9295
* @param {Element} element
93-
* @param {number|null} _1
94-
* @param {Parent|null} _2
96+
* @param {number|null} _
97+
* @param {Parent|null} parent
9598
* @param {SelectState} state
9699
* @returns {boolean}
97100
*/
98-
function matches(query, element, _1, _2, state) {
101+
function matches(query, element, _, parent, state) {
99102
const shallow = state.shallow
100103
const one = state.one
101104

102-
state.shallow = true
105+
state.shallow = false
103106
state.one = true
104107

105108
const result = any(query.value, element, state)[0] === element
@@ -525,12 +528,12 @@ function assertDeep(state, query) {
525528
/**
526529
* @param {RulePseudoSelector} query
527530
* @param {Element} element
528-
* @param {number|null} _2
529-
* @param {Parent|null} _3
531+
* @param {number|null} _1
532+
* @param {Parent|null} _2
530533
* @param {SelectState} state
531534
* @returns {boolean}
532535
*/
533-
function has(query, element, _2, _3, state) {
536+
function has(query, element, _1, _2, state) {
534537
const shallow = state.shallow
535538
const one = state.one
536539
const scopeElements = state.scopeElements

lib/test.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
/**
22
* @typedef {import('./types.js').Rule} Rule
33
* @typedef {import('./types.js').HastNode} HastNode
4-
* @typedef {import('./types.js').Element} Element
54
* @typedef {import('./types.js').Parent} Parent
65
* @typedef {import('./types.js').SelectState} SelectState
7-
* @typedef {import('hast-util-is-element').AssertPredicate<Element>} IsElement
86
*/
97

108
import {attribute} from './attribute.js'

lib/types.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,15 @@
5454
* @property {string} [language]
5555
* @property {Direction} [direction]
5656
* @property {boolean} [editableOrEditingHost]
57-
* @property {number} [typeIndex] Track siblings
58-
* @property {number} [elementIndex] Track siblings
59-
* @property {number} [typeCount] Track siblings
60-
* @property {number} [elementCount] Track siblings
57+
* @property {number} [typeIndex]
58+
* Track siblings: this current element has `n` elements with its tag name
59+
* before it.
60+
* @property {number} [elementIndex]
61+
* Track siblings: this current element has `n` elements before it.
62+
* @property {number} [typeCount]
63+
* Track siblings: there are `n` siblings with this element’s tag name.
64+
* @property {number} [elementCount]
65+
* Track siblings: there are `n` siblings.
6166
*/
6267

6368
/**

test/select-all.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,36 @@ test('select.selectAll()', (t) => {
968968
t.end()
969969
})
970970

971+
t.test(':any', (t) => {
972+
t.deepEqual(
973+
selectAll('y:any(:first-child)', h('x', [h('y#a'), h('y#b')])),
974+
[h('y#a')],
975+
'should support parent-sensitive `:any`'
976+
)
977+
978+
t.end()
979+
})
980+
981+
t.test(':matches', (t) => {
982+
t.deepEqual(
983+
selectAll('y:matches(:first-child)', h('x', [h('y#a'), h('y#b')])),
984+
[h('y#a')],
985+
'should support parent-sensitive `:matches`'
986+
)
987+
988+
t.end()
989+
})
990+
991+
t.test(':not', (t) => {
992+
t.deepEqual(
993+
selectAll('y:not(:first-child)', h('x', [h('y#a'), h('y#b')])),
994+
[h('y#b')],
995+
'should support parent-sensitive `:not`'
996+
)
997+
998+
t.end()
999+
})
1000+
9711001
t.end()
9721002
})
9731003

test/select.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,36 @@ test('select.select()', (t) => {
912912
t.end()
913913
})
914914

915+
t.test(':any', (t) => {
916+
t.deepEqual(
917+
select('y:any(:first-child)', h('x', [h('y#a'), h('y#b')])),
918+
h('y#a'),
919+
'should support parent-sensitive `:any`'
920+
)
921+
922+
t.end()
923+
})
924+
925+
t.test(':matches', (t) => {
926+
t.deepEqual(
927+
select('y:matches(:first-child)', h('x', [h('y#a'), h('y#b')])),
928+
h('y#a'),
929+
'should support parent-sensitive `:matches`'
930+
)
931+
932+
t.end()
933+
})
934+
935+
t.test(':not', (t) => {
936+
t.deepEqual(
937+
select('y:not(:first-child)', h('x', [h('y#a'), h('y#b')])),
938+
h('y#b'),
939+
'should support parent-sensitive `:not`'
940+
)
941+
942+
t.end()
943+
})
944+
915945
t.end()
916946
})
917947

0 commit comments

Comments
 (0)