@@ -30,64 +30,70 @@ export function matchSelector(
3030 log ( 'Element:' , element )
3131 }
3232
33- const handleRules = ( element : VElement , rules : any [ ] ) => {
34- // let pos = 0
33+ const handleRules = ( element : VElement , rules : any [ ] , ruleIndex = 0 ) : boolean => {
34+ if ( ! element || ruleIndex >= rules . length )
35+ return false
36+ const part = rules [ ruleIndex ]
37+ const { type, name, action, value, _ignoreCase = true , data } = part
3538 let success = false
36- for ( const part of rules ) {
37- const { type, name, action, value, _ignoreCase = true , data } = part
38- if ( type === 'attribute' ) {
39- if ( action === 'equals' ) {
40- success = element . getAttribute ( name ) === value
41- if ( debug )
42- log ( 'Attribute equals' , success )
43- }
44- else if ( action === 'start' ) {
45- success = ! ! element . getAttribute ( name ) ?. startsWith ( value )
46- if ( debug )
47- log ( 'Attribute start' , success )
48- }
49- else if ( action === 'end' ) {
50- success = ! ! element . getAttribute ( name ) ?. endsWith ( value )
51- if ( debug )
52- log ( 'Attribute start' , success )
53- }
54- else if ( action === 'element' ) {
55- if ( name === 'class' ) {
56- success = element . classList . contains ( value )
39+ switch ( type ) {
40+ case 'attribute' : {
41+ const attrValue = element . getAttribute ( name )
42+ switch ( action ) {
43+ case 'equals' :
44+ success = attrValue === value
5745 if ( debug )
58- log ( 'Attribute class ' , success )
59- }
60- else {
61- success = ! ! element . getAttribute ( name ) ?. includes ( value )
46+ log ( 'Attribute equals ' , success )
47+ break
48+ case 'start' :
49+ success = ! ! attrValue ?. startsWith ( value )
6250 if ( debug )
63- log ( 'Attribute element' , success )
64- }
65- }
66- else if ( action === 'exists' ) {
67- success = element . hasAttribute ( name )
68- if ( debug )
69- log ( 'Attribute exists' , success )
70- }
71- else if ( action === 'any' ) {
72- success = ! ! element . getAttribute ( name ) ?. includes ( value )
73- if ( debug )
74- log ( 'Attribute any' , success )
75- }
76- else {
77- console . warn ( 'Unknown CSS selector action' , action )
51+ log ( 'Attribute start' , success )
52+ break
53+ case 'end' :
54+ success = ! ! attrValue ?. endsWith ( value )
55+ if ( debug )
56+ log ( 'Attribute end' , success )
57+ break
58+ case 'element' :
59+ if ( name === 'class' ) {
60+ success = element . classList . contains ( value )
61+ if ( debug )
62+ log ( 'Attribute class' , success )
63+ }
64+ else {
65+ success = ! ! attrValue ?. includes ( value )
66+ if ( debug )
67+ log ( 'Attribute element' , success )
68+ }
69+ break
70+ case 'exists' :
71+ success = element . hasAttribute ( name )
72+ if ( debug )
73+ log ( 'Attribute exists' , success )
74+ break
75+ case 'any' :
76+ success = ! ! attrValue ?. includes ( value )
77+ if ( debug )
78+ log ( 'Attribute any' , success )
79+ break
80+ default :
81+ if ( debug )
82+ console . warn ( 'Unknown CSS selector action' , action )
7883 }
84+ break
7985 }
80- else if ( type === 'tag' ) {
86+ case 'tag' :
8187 success = element . tagName === name . toUpperCase ( )
8288 if ( debug )
8389 log ( 'Is tag' , success )
84- }
85- else if ( type === 'universal' ) {
90+ break
91+ case 'universal' :
8692 success = true
8793 if ( debug )
8894 log ( 'Is universal' , success )
89- }
90- else if ( type === 'pseudo' ) {
95+ break
96+ case 'pseudo' :
9197 if ( name === 'not' ) {
9298 let ok = true
9399 data . forEach ( ( rules : any ) => {
@@ -98,21 +104,30 @@ export function matchSelector(
98104 }
99105 if ( debug )
100106 log ( 'Is :not' , success )
101- // } else if (type === 'descendant') {
102- // element = element.
103- }
104- // else if (type === 'descendant') {
105- // for (const child of element.childNodes)
106- // handleRules(child, rules.slice(pos))
107- // }
108- else {
109- console . warn ( 'Unknown CSS selector type' , type , selector , rules )
110- }
111- // log(success, selector, part, element)
112- if ( ! success )
113107 break
114-
115- // pos += 1
108+ case 'descendant' :
109+ // Try to match the next rule part in any descendant
110+ for ( const child of element . childNodes || [ ] ) {
111+ if ( handleRules ( child , rules , ruleIndex + 1 ) ) {
112+ success = true
113+ break
114+ }
115+ }
116+ if ( debug )
117+ log ( 'Is descendant' , success )
118+ break
119+ default :
120+ if ( debug )
121+ console . warn ( 'Unknown CSS selector type' , type , selector , rules )
122+ }
123+ if ( ! success )
124+ return false
125+ // If this was a combinator, we already advanced ruleIndex
126+ if ( type === 'descendant' )
127+ return success
128+ // Move to next rule part
129+ if ( ruleIndex + 1 < rules . length ) {
130+ return handleRules ( element , rules , ruleIndex + 1 )
116131 }
117132 return success
118133 }
0 commit comments