1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-11-01 16:33:06 +01:00

Fix parsing of cosmetic filters with empty-string attribute value

Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/2303
This commit is contained in:
Raymond Hill 2022-09-29 12:54:25 -04:00
parent 5e130d3391
commit 80e17af9fa
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2

View File

@ -1572,9 +1572,8 @@ Parser.prototype.SelectorCompiler = class {
// https://github.com/uBlockOrigin/uBlock-issues/issues/2300
// Unquoted atrtibute values are parsed as Identifier instead of String.
astSerialize(parts) {
astSerializePart(part) {
const out = [];
for ( const part of parts ) {
const { data } = part;
switch ( data.type ) {
case 'AttributeSelector': {
@ -1583,7 +1582,10 @@ Parser.prototype.SelectorCompiler = class {
out.push(`[${name}]`);
break;
}
const value = data.value.value || data.value.name;
let value = data.value.value;
if ( typeof value !== 'string' ) {
value = data.value.name;
}
out.push(`[${name}${data.matcher}"${value}"]`);
break;
}
@ -1615,7 +1617,6 @@ Parser.prototype.SelectorCompiler = class {
}
break;
}
case 'ActionSelector':
case 'PseudoClassSelector':
case 'PseudoElementSelector':
out.push(`:${data.name}`);
@ -1626,15 +1627,39 @@ Parser.prototype.SelectorCompiler = class {
case 'Raw':
out.push(data.value);
break;
case 'Selector':
if ( out.length !== 0 ) { out.push(','); }
break;
case 'TypeSelector':
out.push(data.name);
break;
default:
break;
}
return out.join('');
}
astSerialize(parts) {
const out = [];
for ( const part of parts ) {
const { data } = part;
switch ( data.type ) {
case 'AttributeSelector':
case 'ClassSelector':
case 'Combinator':
case 'Identifier':
case 'IdSelector':
case 'Nth':
case 'PseudoClassSelector':
case 'PseudoElementSelector':
case 'Raw':
case 'TypeSelector':
out.push(this.astSerializePart(part));
break;
case 'Selector':
if ( out.length !== 0 ) { out.push(','); }
break;
default:
break;
}
}
return out.join('');
}
@ -1663,55 +1688,20 @@ Parser.prototype.SelectorCompiler = class {
out.action = [ data.name, args ];
break;
}
case 'AttributeSelector': {
const s = data.matcher
? `[${data.name.name}${data.matcher}"${data.value.value}"]`
: `[${data.name.name}]`;
prelude.push(s);
break;
}
case 'ClassSelector': {
const s = `.${data.name}`;
prelude.push(s);
break;
}
case 'Combinator': {
const s = data.name === ' ' ? ' ' : ` ${data.name} `;
prelude.push(s);
break;
}
case 'IdSelector': {
const s = `#${data.name}`;
prelude.push(s);
break;
}
case 'PseudoClassSelector': {
prelude.push(`:${data.name}`);
if ( Array.isArray(part.args) ) {
prelude.push(`(${this.astSerialize(part.args)})`);
}
break;
}
case 'PseudoElementSelector': {
prelude.push(`::${data.name}`);
if ( Array.isArray(part.args) ) {
prelude.push(`(${this.astSerialize(part.args)})`);
}
break;
}
case 'SelectorList':
case 'AttributeSelector':
case 'ClassSelector':
case 'Combinator':
case 'IdSelector':
case 'PseudoClassSelector':
case 'PseudoElementSelector':
case 'TypeSelector':
prelude.push(this.astSerializePart(part));
break;
case 'Selector':
if ( prelude.length !== 0 ) {
prelude.push(', ');
}
break;
case 'SelectorList':
break;
case 'TypeSelector': {
prelude.push(data.name);
break;
}
case 'ProceduralSelector':
if ( prelude.length !== 0 ) {
if ( tasks.length === 0 ) {