Skip to content

Commit fbc7a0e

Browse files
committed
Properly serialize CSS combinators according to position in selector
Related issue: uBlockOrigin/uBlock-issues#2778 Regression from: bb41d95 The regression occurred because the modified code made the assumption that a leading combinator would never be preceded by whitespace, while the parser didn't prevent this. The parser has been fixed to ensure there is never a leading whitespace in a selector.
1 parent 79cf5f5 commit fbc7a0e

File tree

1 file changed

+30
-3
lines changed

1 file changed

+30
-3
lines changed

src/js/static-filtering-parser.js

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3364,7 +3364,7 @@ class ExtSelectorCompiler {
33643364
out.push(`.${data.name}`);
33653365
break;
33663366
case 'Combinator':
3367-
out.push(data.name === ' ' ? ' ' : ` ${data.name} `);
3367+
out.push(data.name);
33683368
break;
33693369
case 'Identifier':
33703370
if ( this.reInvalidIdentifier.test(data.name) ) { return; }
@@ -3436,14 +3436,35 @@ class ExtSelectorCompiler {
34363436
return out.join('');
34373437
}
34383438

3439+
astAppendPart(part, out) {
3440+
const { data } = part;
3441+
switch ( data.type ) {
3442+
case 'Combinator': {
3443+
const s = this.astSerializePart(part);
3444+
if ( s === undefined ) { return false; }
3445+
if ( out.length === 0 ) {
3446+
if ( s !== ' ' ) {
3447+
out.push(s, ' ');
3448+
}
3449+
} else {
3450+
out.push(' ');
3451+
if ( s !== ' ' ) {
3452+
out.push(s, ' ');
3453+
}
3454+
}
3455+
break;
3456+
}
3457+
}
3458+
return true;
3459+
}
3460+
34393461
astSerialize(parts, plainCSS = true) {
34403462
const out = [];
34413463
for ( const part of parts ) {
34423464
const { data } = part;
34433465
switch ( data.type ) {
34443466
case 'AttributeSelector':
34453467
case 'ClassSelector':
3446-
case 'Combinator':
34473468
case 'Identifier':
34483469
case 'IdSelector':
34493470
case 'Nth':
@@ -3455,6 +3476,9 @@ class ExtSelectorCompiler {
34553476
out.push(s);
34563477
break;
34573478
}
3479+
case 'Combinator':
3480+
if ( this.astAppendPart(part, out) === false ) { return; }
3481+
break;
34583482
case 'Raw':
34593483
if ( plainCSS ) { return; }
34603484
out.push(this.astSerializePart(part));
@@ -3499,7 +3523,6 @@ class ExtSelectorCompiler {
34993523
}
35003524
case 'AttributeSelector':
35013525
case 'ClassSelector':
3502-
case 'Combinator':
35033526
case 'IdSelector':
35043527
case 'PseudoClassSelector':
35053528
case 'PseudoElementSelector':
@@ -3509,6 +3532,10 @@ class ExtSelectorCompiler {
35093532
prelude.push(component);
35103533
break;
35113534
}
3535+
case 'Combinator': {
3536+
if ( this.astAppendPart(part, prelude) === false ) { return; }
3537+
break;
3538+
}
35123539
case 'ProceduralSelector': {
35133540
if ( prelude.length !== 0 ) {
35143541
let spath = prelude.join('');

0 commit comments

Comments
 (0)