mirror of
https://github.com/gorhill/uBlock.git
synced 2024-09-15 15:32:28 +02: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:
parent
5e130d3391
commit
80e17af9fa
@ -1572,66 +1572,91 @@ Parser.prototype.SelectorCompiler = class {
|
|||||||
|
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/2300
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/2300
|
||||||
// Unquoted atrtibute values are parsed as Identifier instead of String.
|
// Unquoted atrtibute values are parsed as Identifier instead of String.
|
||||||
|
astSerializePart(part) {
|
||||||
|
const out = [];
|
||||||
|
const { data } = part;
|
||||||
|
switch ( data.type ) {
|
||||||
|
case 'AttributeSelector': {
|
||||||
|
const name = data.name.name;
|
||||||
|
if ( data.matcher === null ) {
|
||||||
|
out.push(`[${name}]`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let value = data.value.value;
|
||||||
|
if ( typeof value !== 'string' ) {
|
||||||
|
value = data.value.name;
|
||||||
|
}
|
||||||
|
out.push(`[${name}${data.matcher}"${value}"]`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'ClassSelector':
|
||||||
|
out.push(`.${data.name}`);
|
||||||
|
break;
|
||||||
|
case 'Combinator':
|
||||||
|
out.push(data.name === ' ' ? ' ' : ` ${data.name} `);
|
||||||
|
break;
|
||||||
|
case 'Identifier':
|
||||||
|
out.push(data.name);
|
||||||
|
break;
|
||||||
|
case 'IdSelector':
|
||||||
|
out.push(`#${data.name}`);
|
||||||
|
break;
|
||||||
|
case 'Nth': {
|
||||||
|
const a = parseInt(data.nth.a, 10) || null;
|
||||||
|
const b = parseInt(data.nth.b, 10) || null;
|
||||||
|
if ( a !== null ) {
|
||||||
|
out.push(`${a}n`);
|
||||||
|
if ( b === null ) { break; }
|
||||||
|
if ( b < 0 ) {
|
||||||
|
out.push(`${b}`);
|
||||||
|
} else {
|
||||||
|
out.push(`+${b}`);
|
||||||
|
}
|
||||||
|
} else if ( b !== null ) {
|
||||||
|
out.push(`${b}`);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'PseudoClassSelector':
|
||||||
|
case 'PseudoElementSelector':
|
||||||
|
out.push(`:${data.name}`);
|
||||||
|
if ( Array.isArray(part.args) ) {
|
||||||
|
out.push(`(${this.astSerialize(part.args)})`);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'Raw':
|
||||||
|
out.push(data.value);
|
||||||
|
break;
|
||||||
|
case 'TypeSelector':
|
||||||
|
out.push(data.name);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return out.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
astSerialize(parts) {
|
astSerialize(parts) {
|
||||||
const out = [];
|
const out = [];
|
||||||
for ( const part of parts ) {
|
for ( const part of parts ) {
|
||||||
const { data } = part;
|
const { data } = part;
|
||||||
switch ( data.type ) {
|
switch ( data.type ) {
|
||||||
case 'AttributeSelector': {
|
case 'AttributeSelector':
|
||||||
const name = data.name.name;
|
|
||||||
if ( data.matcher === null ) {
|
|
||||||
out.push(`[${name}]`);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const value = data.value.value || data.value.name;
|
|
||||||
out.push(`[${name}${data.matcher}"${value}"]`);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'ClassSelector':
|
case 'ClassSelector':
|
||||||
out.push(`.${data.name}`);
|
|
||||||
break;
|
|
||||||
case 'Combinator':
|
case 'Combinator':
|
||||||
out.push(data.name === ' ' ? ' ' : ` ${data.name} `);
|
|
||||||
break;
|
|
||||||
case 'Identifier':
|
case 'Identifier':
|
||||||
out.push(data.name);
|
|
||||||
break;
|
|
||||||
case 'IdSelector':
|
case 'IdSelector':
|
||||||
out.push(`#${data.name}`);
|
case 'Nth':
|
||||||
break;
|
|
||||||
case 'Nth': {
|
|
||||||
const a = parseInt(data.nth.a, 10) || null;
|
|
||||||
const b = parseInt(data.nth.b, 10) || null;
|
|
||||||
if ( a !== null ) {
|
|
||||||
out.push(`${a}n`);
|
|
||||||
if ( b === null ) { break; }
|
|
||||||
if ( b < 0 ) {
|
|
||||||
out.push(`${b}`);
|
|
||||||
} else {
|
|
||||||
out.push(`+${b}`);
|
|
||||||
}
|
|
||||||
} else if ( b !== null ) {
|
|
||||||
out.push(`${b}`);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'ActionSelector':
|
|
||||||
case 'PseudoClassSelector':
|
case 'PseudoClassSelector':
|
||||||
case 'PseudoElementSelector':
|
case 'PseudoElementSelector':
|
||||||
out.push(`:${data.name}`);
|
|
||||||
if ( Array.isArray(part.args) ) {
|
|
||||||
out.push(`(${this.astSerialize(part.args)})`);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'Raw':
|
case 'Raw':
|
||||||
out.push(data.value);
|
case 'TypeSelector':
|
||||||
|
out.push(this.astSerializePart(part));
|
||||||
break;
|
break;
|
||||||
case 'Selector':
|
case 'Selector':
|
||||||
if ( out.length !== 0 ) { out.push(','); }
|
if ( out.length !== 0 ) { out.push(','); }
|
||||||
break;
|
break;
|
||||||
case 'TypeSelector':
|
|
||||||
out.push(data.name);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1663,55 +1688,20 @@ Parser.prototype.SelectorCompiler = class {
|
|||||||
out.action = [ data.name, args ];
|
out.action = [ data.name, args ];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'AttributeSelector': {
|
case 'AttributeSelector':
|
||||||
const s = data.matcher
|
case 'ClassSelector':
|
||||||
? `[${data.name.name}${data.matcher}"${data.value.value}"]`
|
case 'Combinator':
|
||||||
: `[${data.name.name}]`;
|
case 'IdSelector':
|
||||||
prelude.push(s);
|
case 'PseudoClassSelector':
|
||||||
break;
|
case 'PseudoElementSelector':
|
||||||
}
|
case 'TypeSelector':
|
||||||
case 'ClassSelector': {
|
prelude.push(this.astSerializePart(part));
|
||||||
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':
|
|
||||||
break;
|
break;
|
||||||
case 'Selector':
|
case 'Selector':
|
||||||
if ( prelude.length !== 0 ) {
|
if ( prelude.length !== 0 ) {
|
||||||
prelude.push(', ');
|
prelude.push(', ');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'SelectorList':
|
|
||||||
break;
|
|
||||||
case 'TypeSelector': {
|
|
||||||
prelude.push(data.name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'ProceduralSelector':
|
case 'ProceduralSelector':
|
||||||
if ( prelude.length !== 0 ) {
|
if ( prelude.length !== 0 ) {
|
||||||
if ( tasks.length === 0 ) {
|
if ( tasks.length === 0 ) {
|
||||||
|
Loading…
Reference in New Issue
Block a user