mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-24 11:22:44 +01:00
fix regression in 8f05a2f8d3
(related issue: #3683)
This commit is contained in:
parent
08d4604e31
commit
d3a3505a54
@ -146,7 +146,7 @@
|
||||
};
|
||||
|
||||
const compileProceduralSelector = (function() {
|
||||
var reProceduralOperator = new RegExp([
|
||||
const reProceduralOperator = new RegExp([
|
||||
'^(?:',
|
||||
[
|
||||
'-abp-contains',
|
||||
@ -165,17 +165,17 @@
|
||||
')\\('
|
||||
].join(''));
|
||||
|
||||
var reEscapeRegex = /[.*+?^${}()|[\]\\]/g,
|
||||
const reEscapeRegex = /[.*+?^${}()|[\]\\]/g,
|
||||
reNeedScope = /^\s*[+>~]/,
|
||||
reIsDanglingSelector = /(?:[+>~]\s*|\s+)$/;
|
||||
|
||||
var lastProceduralSelector = '',
|
||||
lastProceduralSelectorCompiled,
|
||||
regexToRawValue = new Map();
|
||||
const regexToRawValue = new Map();
|
||||
let lastProceduralSelector = '',
|
||||
lastProceduralSelectorCompiled;
|
||||
|
||||
var compileText = function(s) {
|
||||
var regexDetails,
|
||||
match = reParseRegexLiteral.exec(s);
|
||||
const compileText = function(s) {
|
||||
const match = reParseRegexLiteral.exec(s);
|
||||
let regexDetails;
|
||||
if ( match !== null ) {
|
||||
regexDetails = match[1];
|
||||
if ( isBadRegex(regexDetails) ) { return; }
|
||||
@ -189,13 +189,13 @@
|
||||
return regexDetails;
|
||||
};
|
||||
|
||||
var compileCSSDeclaration = function(s) {
|
||||
var name, value, regexDetails,
|
||||
pos = s.indexOf(':');
|
||||
const compileCSSDeclaration = function(s) {
|
||||
const pos = s.indexOf(':');
|
||||
if ( pos === -1 ) { return; }
|
||||
name = s.slice(0, pos).trim();
|
||||
value = s.slice(pos + 1).trim();
|
||||
var match = reParseRegexLiteral.exec(value);
|
||||
const name = s.slice(0, pos).trim();
|
||||
const value = s.slice(pos + 1).trim();
|
||||
const match = reParseRegexLiteral.exec(value);
|
||||
let regexDetails;
|
||||
if ( match !== null ) {
|
||||
regexDetails = match[1];
|
||||
if ( isBadRegex(regexDetails) ) { return; }
|
||||
@ -209,10 +209,7 @@
|
||||
return { name: name, value: regexDetails };
|
||||
};
|
||||
|
||||
var compileConditionalSelector = function(s) {
|
||||
if ( isValidCSSSelector(s) ) {
|
||||
return { selector: s, tasks: [] };
|
||||
}
|
||||
const compileConditionalSelector = function(s) {
|
||||
// https://github.com/AdguardTeam/ExtendedCss/issues/31#issuecomment-302391277
|
||||
// Prepend `:scope ` if needed.
|
||||
if ( reNeedScope.test(s) ) {
|
||||
@ -221,7 +218,17 @@
|
||||
return compile(s);
|
||||
};
|
||||
|
||||
var compileXpathExpression = function(s) {
|
||||
const compileNotSelector = function(s) {
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/341#issuecomment-447603588
|
||||
// Reject instances of :not() filters for which the argument is
|
||||
// a valid CSS selector, otherwise we would be adversely
|
||||
// changing the behavior of CSS4's :not().
|
||||
if ( isValidCSSSelector(s) === false ) {
|
||||
return compileConditionalSelector(s);
|
||||
}
|
||||
};
|
||||
|
||||
const compileXpathExpression = function(s) {
|
||||
try {
|
||||
document.createExpression(s, null);
|
||||
} catch (e) {
|
||||
@ -231,13 +238,13 @@
|
||||
};
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/2793
|
||||
var normalizedOperators = new Map([
|
||||
const normalizedOperators = new Map([
|
||||
[ ':-abp-contains', ':has-text' ],
|
||||
[ ':-abp-has', ':has' ],
|
||||
[ ':contains', ':has-text' ],
|
||||
]);
|
||||
|
||||
var compileArgument = new Map([
|
||||
const compileArgument = new Map([
|
||||
[ ':has', compileConditionalSelector ],
|
||||
[ ':has-text', compileText ],
|
||||
[ ':if', compileConditionalSelector ],
|
||||
@ -245,7 +252,7 @@
|
||||
[ ':matches-css', compileCSSDeclaration ],
|
||||
[ ':matches-css-after', compileCSSDeclaration ],
|
||||
[ ':matches-css-before', compileCSSDeclaration ],
|
||||
[ ':not', compileConditionalSelector ],
|
||||
[ ':not', compileNotSelector ],
|
||||
[ ':xpath', compileXpathExpression ]
|
||||
]);
|
||||
|
||||
@ -256,15 +263,14 @@
|
||||
// to other blockers.
|
||||
// The normalized string version is what is reported in the logger,
|
||||
// by design.
|
||||
var decompile = function(compiled) {
|
||||
var tasks = compiled.tasks;
|
||||
const decompile = function(compiled) {
|
||||
const tasks = compiled.tasks;
|
||||
if ( Array.isArray(tasks) === false ) {
|
||||
return compiled.selector;
|
||||
}
|
||||
var raw = [ compiled.selector ],
|
||||
value;
|
||||
for ( var i = 0, n = tasks.length, task; i < n; i++ ) {
|
||||
task = tasks[i];
|
||||
const raw = [ compiled.selector ];
|
||||
let value;
|
||||
for ( let task of tasks ) {
|
||||
switch ( task[0] ) {
|
||||
case ':xpath':
|
||||
raw.push(task[0], '(', task[1], ')');
|
||||
@ -306,14 +312,15 @@
|
||||
return raw.join('');
|
||||
};
|
||||
|
||||
var compile = function(raw) {
|
||||
const compile = function(raw) {
|
||||
if ( raw === '' ) { return; }
|
||||
var prefix = '',
|
||||
let prefix = '',
|
||||
tasks = [];
|
||||
let i = 0,
|
||||
n = raw.length,
|
||||
opPrefixBeg = 0;
|
||||
for (;;) {
|
||||
var i = 0,
|
||||
n = raw.length,
|
||||
c, match;
|
||||
let c, match;
|
||||
// Advance to next operator.
|
||||
while ( i < n ) {
|
||||
c = raw.charCodeAt(i++);
|
||||
@ -323,14 +330,14 @@
|
||||
}
|
||||
}
|
||||
if ( i === n ) { break; }
|
||||
var opNameBeg = i - 1;
|
||||
var opNameEnd = i + match[0].length - 1;
|
||||
const opNameBeg = i - 1;
|
||||
const opNameEnd = i + match[0].length - 1;
|
||||
i += match[0].length;
|
||||
// Find end of argument: first balanced closing parenthesis.
|
||||
// Note: unbalanced parenthesis can be used in a regex literal
|
||||
// when they are escaped using `\`.
|
||||
// TODO: need to handle quoted parentheses.
|
||||
var pcnt = 1;
|
||||
let pcnt = 1;
|
||||
while ( i < n ) {
|
||||
c = raw.charCodeAt(i++);
|
||||
if ( c === 0x5C /* '\\' */ ) {
|
||||
@ -345,27 +352,39 @@
|
||||
// Unbalanced parenthesis? An unbalanced parenthesis is fine
|
||||
// as long as the last character is a closing parenthesis.
|
||||
if ( pcnt !== 0 && c !== 0x29 ) { return; }
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/341#issuecomment-447603588
|
||||
// Maybe that one operator is a valid CSS selector and if so,
|
||||
// then consider it to be part of the prefix. If there is
|
||||
// at least one task present, then we fail, as we do not
|
||||
// support suffix CSS selectors.
|
||||
// TODO: AdGuard does support suffix CSS selectors, so
|
||||
// supporting this would increase compatibility with
|
||||
// AdGuard filter lists.
|
||||
if ( isValidCSSSelector(raw.slice(opNameBeg, i)) ) {
|
||||
if ( opPrefixBeg !== 0 ) { return; }
|
||||
continue;
|
||||
}
|
||||
// Extract and remember operator details.
|
||||
var operator = raw.slice(opNameBeg, opNameEnd);
|
||||
let operator = raw.slice(opNameBeg, opNameEnd);
|
||||
operator = normalizedOperators.get(operator) || operator;
|
||||
var args = raw.slice(opNameEnd + 1, i - 1);
|
||||
let args = raw.slice(opNameEnd + 1, i - 1);
|
||||
args = compileArgument.get(operator)(args);
|
||||
if ( args === undefined ) { return; }
|
||||
if ( tasks.length === 0 ) {
|
||||
if ( opPrefixBeg === 0 ) {
|
||||
prefix = raw.slice(0, opNameBeg);
|
||||
} else if ( opNameBeg !== 0 ) {
|
||||
} else if ( opNameBeg !== opPrefixBeg ) {
|
||||
return;
|
||||
}
|
||||
tasks.push([ operator, args ]);
|
||||
raw = raw.slice(i);
|
||||
if ( i === n ) { break; }
|
||||
opPrefixBeg = i;
|
||||
}
|
||||
// No task found: then we have a CSS selector.
|
||||
// At least one task found: nothing should be left to parse.
|
||||
if ( tasks.length === 0 ) {
|
||||
prefix = raw;
|
||||
tasks = undefined;
|
||||
} else if ( raw.length !== 0 ) {
|
||||
} else if ( i < n ) {
|
||||
return;
|
||||
}
|
||||
// https://github.com/NanoAdblocker/NanoCore/issues/1#issuecomment-354394894
|
||||
@ -376,7 +395,7 @@
|
||||
return { selector: prefix, tasks: tasks };
|
||||
};
|
||||
|
||||
var entryPoint = function(raw) {
|
||||
const entryPoint = function(raw) {
|
||||
if ( raw === lastProceduralSelector ) {
|
||||
return lastProceduralSelectorCompiled;
|
||||
}
|
||||
@ -391,7 +410,7 @@
|
||||
};
|
||||
|
||||
entryPoint.reset = function() {
|
||||
regexToRawValue = new Map();
|
||||
regexToRawValue.clear();
|
||||
lastProceduralSelector = '';
|
||||
lastProceduralSelectorCompiled = undefined;
|
||||
};
|
||||
@ -403,7 +422,18 @@
|
||||
// Public API
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
var api = {};
|
||||
const api = {
|
||||
get acceptedCount() {
|
||||
return µb.cosmeticFilteringEngine.acceptedCount +
|
||||
µb.scriptletFilteringEngine.acceptedCount +
|
||||
µb.htmlFilteringEngine.acceptedCount;
|
||||
},
|
||||
get discardedCount() {
|
||||
return µb.cosmeticFilteringEngine.discardedCount +
|
||||
µb.scriptletFilteringEngine.discardedCount +
|
||||
µb.htmlFilteringEngine.discardedCount;
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public classes
|
||||
@ -464,12 +494,12 @@
|
||||
};
|
||||
|
||||
api.HostnameBasedDB.prototype[Symbol.iterator] = (function() {
|
||||
var Iter = function(db) {
|
||||
const Iter = function(db) {
|
||||
this.mapIter = db.values();
|
||||
this.arrayIter = undefined;
|
||||
};
|
||||
Iter.prototype.next = function() {
|
||||
var result;
|
||||
let result;
|
||||
if ( this.arrayIter !== undefined ) {
|
||||
result = this.arrayIter.next();
|
||||
if ( result.done === false ) { return result; }
|
||||
@ -516,11 +546,11 @@
|
||||
// Based on: FNV32a
|
||||
// http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-reference-source
|
||||
// The rest is custom, suited for uBlock.
|
||||
let i1 = token.length;
|
||||
const i1 = token.length;
|
||||
if ( i1 === 0 ) { return 0; }
|
||||
let i2 = i1 >> 1;
|
||||
let i4 = i1 >> 2;
|
||||
let i8 = i1 >> 3;
|
||||
const i2 = i1 >> 1;
|
||||
const i4 = i1 >> 2;
|
||||
const i8 = i1 >> 3;
|
||||
let hval = (0x811c9dc5 ^ token.charCodeAt(0)) >>> 0;
|
||||
hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24);
|
||||
hval >>>= 0;
|
||||
@ -553,7 +583,7 @@
|
||||
api.compileHostnameToHash = function(hostname) {
|
||||
let domain;
|
||||
if ( hostname.endsWith('.*') ) {
|
||||
let pos = hostname.lastIndexOf('.', hostname.length - 3);
|
||||
const pos = hostname.lastIndexOf('.', hostname.length - 3);
|
||||
domain = pos !== -1 ? hostname.slice(pos + 1) : hostname;
|
||||
} else {
|
||||
domain = µb.URI.domainFromHostnameNoCache(hostname);
|
||||
@ -575,14 +605,14 @@
|
||||
// Do not discard unknown pseudo-elements.
|
||||
|
||||
api.compileSelector = (function() {
|
||||
var reAfterBeforeSelector = /^(.+?)(::?after|::?before|::[a-z-]+)$/,
|
||||
reStyleSelector = /^(.+?):style\((.+?)\)$/,
|
||||
reStyleBad = /url\([^)]+\)/,
|
||||
reExtendedSyntax = /\[-(?:abp|ext)-[a-z-]+=(['"])(?:.+?)(?:\1)\]/,
|
||||
reExtendedSyntaxParser = /\[-(?:abp|ext)-([a-z-]+)=(['"])(.+?)\2\]/,
|
||||
div = document.createElement('div');
|
||||
const reAfterBeforeSelector = /^(.+?)(::?after|::?before|::[a-z-]+)$/;
|
||||
const reStyleSelector = /^(.+?):style\((.+?)\)$/;
|
||||
const reStyleBad = /url\([^)]+\)/;
|
||||
const reExtendedSyntax = /\[-(?:abp|ext)-[a-z-]+=(['"])(?:.+?)(?:\1)\]/;
|
||||
const reExtendedSyntaxParser = /\[-(?:abp|ext)-([a-z-]+)=(['"])(.+?)\2\]/;
|
||||
const div = document.createElement('div');
|
||||
|
||||
var normalizedExtendedSyntaxOperators = new Map([
|
||||
const normalizedExtendedSyntaxOperators = new Map([
|
||||
[ 'contains', ':has-text' ],
|
||||
[ 'has', ':has' ],
|
||||
[ 'matches-css', ':matches-css' ],
|
||||
@ -590,7 +620,7 @@
|
||||
[ 'matches-css-before', ':matches-css-before' ],
|
||||
]);
|
||||
|
||||
var isValidStyleProperty = function(cssText) {
|
||||
const isValidStyleProperty = function(cssText) {
|
||||
if ( reStyleBad.test(cssText) ) { return false; }
|
||||
div.style.cssText = cssText;
|
||||
if ( div.style.cssText === '' ) { return false; }
|
||||
@ -598,8 +628,8 @@
|
||||
return true;
|
||||
};
|
||||
|
||||
var entryPoint = function(raw) {
|
||||
var extendedSyntax = reExtendedSyntax.test(raw);
|
||||
const entryPoint = function(raw) {
|
||||
const extendedSyntax = reExtendedSyntax.test(raw);
|
||||
if ( isValidCSSSelector(raw) && extendedSyntax === false ) {
|
||||
return raw;
|
||||
}
|
||||
@ -607,7 +637,7 @@
|
||||
// We rarely reach this point -- majority of selectors are plain
|
||||
// CSS selectors.
|
||||
|
||||
var matches, operator;
|
||||
let matches, operator;
|
||||
|
||||
// Supported Adguard/ABP advanced selector syntax: will translate into
|
||||
// uBO's syntax before further processing.
|
||||
@ -627,7 +657,7 @@
|
||||
return entryPoint(raw);
|
||||
}
|
||||
|
||||
var selector = raw,
|
||||
let selector = raw,
|
||||
pseudoclass, style;
|
||||
|
||||
// `:style` selector?
|
||||
@ -664,7 +694,7 @@
|
||||
}
|
||||
|
||||
// Procedural selector?
|
||||
var compiled;
|
||||
let compiled;
|
||||
if ( (compiled = compileProceduralSelector(raw)) ) {
|
||||
return compiled;
|
||||
}
|
||||
@ -770,23 +800,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
Object.defineProperties(api, {
|
||||
acceptedCount: {
|
||||
get: function() {
|
||||
return µb.cosmeticFilteringEngine.acceptedCount +
|
||||
µb.scriptletFilteringEngine.acceptedCount +
|
||||
µb.htmlFilteringEngine.acceptedCount;
|
||||
}
|
||||
},
|
||||
discardedCount: {
|
||||
get: function() {
|
||||
return µb.cosmeticFilteringEngine.discardedCount +
|
||||
µb.scriptletFilteringEngine.discardedCount +
|
||||
µb.htmlFilteringEngine.discardedCount;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
api.fromSelfie = function(selfie) {
|
||||
µb.cosmeticFilteringEngine.fromSelfie(selfie.cosmetic);
|
||||
µb.scriptletFilteringEngine.fromSelfie(selfie.scriptlets);
|
||||
|
Loading…
Reference in New Issue
Block a user