mirror of
https://github.com/gorhill/uBlock.git
synced 2026-03-11 09:04:36 +00:00
[mv3] Add support for ancestor context syntax in scriptlets
Related commit:
a483f7955f
This commit is contained in:
parent
536f0fba25
commit
d006fd06e7
3 changed files with 81 additions and 110 deletions
|
|
@ -1526,8 +1526,8 @@ async function main() {
|
|||
|
||||
await rulesetFromURLs({
|
||||
id: 'est-0',
|
||||
group: 'regions',
|
||||
lang: 'et',
|
||||
group: 'regions',
|
||||
lang: 'et',
|
||||
name: '🇪🇪ee: Eesti saitidele kohandatud filter',
|
||||
enabled: false,
|
||||
urls: [ 'https://ubol-et.adblock.ee/list.txt' ],
|
||||
|
|
|
|||
|
|
@ -97,8 +97,9 @@ export function compile(assetDetails, details) {
|
|||
world: resourceEntry.world,
|
||||
args: new Map(),
|
||||
hostnames: new Map(),
|
||||
entities: new Map(),
|
||||
exceptions: new Map(),
|
||||
hasEntities: false,
|
||||
hasAncestors: false,
|
||||
matches: new Set(),
|
||||
});
|
||||
}
|
||||
|
|
@ -109,23 +110,21 @@ export function compile(assetDetails, details) {
|
|||
const iArgs = scriptletDetails.args.get(argsToken);
|
||||
if ( details.matches ) {
|
||||
for ( const hn of details.matches ) {
|
||||
if ( hn.endsWith('.*') ) {
|
||||
const isEntity = hn.endsWith('.*') || hn.endsWith('.*>>');
|
||||
scriptletDetails.hasEntities ||= isEntity;
|
||||
const isAncestor = hn.endsWith('>>')
|
||||
scriptletDetails.hasAncestors ||= isAncestor;
|
||||
if ( isEntity || isAncestor ) {
|
||||
scriptletDetails.matches.clear();
|
||||
scriptletDetails.matches.add('*');
|
||||
const entity = hn.slice(0, -2);
|
||||
if ( scriptletDetails.entities.has(entity) === false ) {
|
||||
scriptletDetails.entities.set(entity, new Set());
|
||||
}
|
||||
scriptletDetails.entities.get(entity).add(iArgs);
|
||||
} else {
|
||||
if ( scriptletDetails.matches.has('*') === false ) {
|
||||
scriptletDetails.matches.add(hn);
|
||||
}
|
||||
if ( scriptletDetails.hostnames.has(hn) === false ) {
|
||||
scriptletDetails.hostnames.set(hn, new Set());
|
||||
}
|
||||
scriptletDetails.hostnames.get(hn).add(iArgs);
|
||||
}
|
||||
if ( scriptletDetails.matches.has('*') === false ) {
|
||||
scriptletDetails.matches.add(hn);
|
||||
}
|
||||
if ( scriptletDetails.hostnames.has(hn) === false ) {
|
||||
scriptletDetails.hostnames.set(hn, new Set());
|
||||
}
|
||||
scriptletDetails.hostnames.get(hn).add(iArgs);
|
||||
}
|
||||
} else {
|
||||
scriptletDetails.matches.add('*');
|
||||
|
|
@ -172,8 +171,12 @@ export async function commit(rulesetId, path, writeFn) {
|
|||
JSON.stringify(patchHnMap(details.hostnames))
|
||||
);
|
||||
content = safeReplace(content,
|
||||
'self.$entitiesMap$',
|
||||
JSON.stringify(patchHnMap(details.entities))
|
||||
'self.$hasEntities$',
|
||||
JSON.stringify(details.hasEntities)
|
||||
);
|
||||
content = safeReplace(content,
|
||||
'self.$hasAncestors$',
|
||||
JSON.stringify(details.hasAncestors)
|
||||
);
|
||||
content = safeReplace(content,
|
||||
'self.$exceptionsMap$',
|
||||
|
|
|
|||
|
|
@ -20,30 +20,13 @@
|
|||
|
||||
*/
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
// ruleset: $rulesetId$
|
||||
|
||||
// Important!
|
||||
// Isolate from global scope
|
||||
|
||||
// Start of local scope
|
||||
(( ) => {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Start of code to inject
|
||||
const uBOL_$scriptletName$ = function() {
|
||||
|
||||
const scriptletGlobals = {}; // eslint-disable-line
|
||||
|
||||
const argsList = self.$argsList$;
|
||||
|
||||
const hostnamesMap = new Map(self.$hostnamesMap$);
|
||||
|
||||
const entitiesMap = new Map(self.$entitiesMap$);
|
||||
|
||||
const exceptionsMap = new Map(self.$exceptionsMap$);
|
||||
(function uBOL_$scriptletName$() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
@ -51,98 +34,83 @@ function $scriptletName$(){}
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
const hnParts = [];
|
||||
try {
|
||||
let origin = document.location.origin;
|
||||
if ( origin === 'null' ) {
|
||||
const origins = document.location.ancestorOrigins || [];
|
||||
for ( let i = 0; i < origins.length; i++ ) {
|
||||
origin = origins[i];
|
||||
if ( origin !== 'null' ) { break; }
|
||||
}
|
||||
}
|
||||
const beg = origin.lastIndexOf('://');
|
||||
if ( beg === -1 ) { return; }
|
||||
let hn = origin.slice(beg+3)
|
||||
const end = hn.indexOf(':');
|
||||
if ( end !== -1 ) { hn = hn.slice(0, end); }
|
||||
hnParts.push(...hn.split('.'));
|
||||
} catch {
|
||||
}
|
||||
const hnpartslen = hnParts.length;
|
||||
if ( hnpartslen === 0 ) { return; }
|
||||
const scriptletGlobals = {}; // eslint-disable-line
|
||||
const argsList = self.$argsList$;
|
||||
const hostnamesMap = new Map(self.$hostnamesMap$);
|
||||
const exceptionsMap = new Map(self.$exceptionsMap$);
|
||||
const hasEntities = self.$hasEntities$;
|
||||
const hasAncestors = self.$hasAncestors$;
|
||||
|
||||
const todoIndices = new Set();
|
||||
const tonotdoIndices = [];
|
||||
|
||||
// Exceptions
|
||||
if ( exceptionsMap.size !== 0 ) {
|
||||
for ( let i = 0; i < hnpartslen; i++ ) {
|
||||
const hn = hnParts.slice(i).join('.');
|
||||
const excepted = exceptionsMap.get(hn);
|
||||
if ( excepted ) { tonotdoIndices.push(...excepted); }
|
||||
}
|
||||
exceptionsMap.clear();
|
||||
}
|
||||
|
||||
// Hostname-based
|
||||
if ( hostnamesMap.size !== 0 ) {
|
||||
const collectArgIndices = hn => {
|
||||
let argsIndices = hostnamesMap.get(hn);
|
||||
if ( argsIndices === undefined ) { return; }
|
||||
if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; }
|
||||
const collectArgIndices = (hn, map, out) => {
|
||||
let argsIndices = map.get(hn);
|
||||
if ( argsIndices === undefined ) { return; }
|
||||
if ( typeof argsIndices !== 'number' ) {
|
||||
for ( const argsIndex of argsIndices ) {
|
||||
if ( tonotdoIndices.includes(argsIndex) ) { continue; }
|
||||
todoIndices.add(argsIndex);
|
||||
out.add(argsIndex);
|
||||
}
|
||||
};
|
||||
for ( let i = 0; i < hnpartslen; i++ ) {
|
||||
const hn = hnParts.slice(i).join('.');
|
||||
collectArgIndices(hn);
|
||||
} else {
|
||||
out.add(argsIndices);
|
||||
}
|
||||
collectArgIndices('*');
|
||||
hostnamesMap.clear();
|
||||
}
|
||||
};
|
||||
|
||||
// Entity-based
|
||||
if ( entitiesMap.size !== 0 ) {
|
||||
const n = hnpartslen - 1;
|
||||
for ( let i = 0; i < n; i++ ) {
|
||||
for ( let j = n; j > i; j-- ) {
|
||||
const en = hnParts.slice(i,j).join('.');
|
||||
let argsIndices = entitiesMap.get(en);
|
||||
if ( argsIndices === undefined ) { continue; }
|
||||
if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; }
|
||||
for ( const argsIndex of argsIndices ) {
|
||||
if ( tonotdoIndices.includes(argsIndex) ) { continue; }
|
||||
todoIndices.add(argsIndex);
|
||||
const indicesFromHostname = (hostname, suffix = '') => {
|
||||
const hnParts = hostname.split('.');
|
||||
const hnpartslen = hnParts.length;
|
||||
if ( hnpartslen === 0 ) { return; }
|
||||
for ( let i = 0; i < hnpartslen; i++ ) {
|
||||
const hn = `${hnParts.slice(i).join('.')}${suffix}`;
|
||||
collectArgIndices(hn, hostnamesMap, todoIndices);
|
||||
collectArgIndices(hn, exceptionsMap, tonotdoIndices);
|
||||
}
|
||||
if ( hasEntities ) {
|
||||
const n = hnpartslen - 1;
|
||||
for ( let i = 0; i < n; i++ ) {
|
||||
for ( let j = n; j > i; j-- ) {
|
||||
const en = `${hnParts.slice(i,j).join('.')}.*${suffix}`;
|
||||
collectArgIndices(en, hostnamesMap, todoIndices);
|
||||
collectArgIndices(en, exceptionsMap, tonotdoIndices);
|
||||
}
|
||||
}
|
||||
}
|
||||
entitiesMap.clear();
|
||||
};
|
||||
|
||||
const entries = (( ) => {
|
||||
const docloc = document.location;
|
||||
const origins = [ docloc.origin ];
|
||||
if ( docloc.ancestorOrigins ) {
|
||||
origins.push(...docloc.ancestorOrigins);
|
||||
}
|
||||
return origins.map((origin, i) => {
|
||||
const beg = origin.lastIndexOf('://');
|
||||
if ( beg === -1 ) { return; }
|
||||
const hn = origin.slice(beg+3)
|
||||
const end = hn.indexOf(':');
|
||||
return { hn: end === -1 ? hn : hn.slice(0, end), i };
|
||||
}).filter(a => a !== undefined);
|
||||
})();
|
||||
if ( entries.length === 0 ) { return; }
|
||||
|
||||
const todoIndices = new Set();
|
||||
const tonotdoIndices = new Set();
|
||||
|
||||
indicesFromHostname(entries[0].hn);
|
||||
if ( hasAncestors ) {
|
||||
for ( const entry of entries ) {
|
||||
if ( entry.i === 0 ) { continue; }
|
||||
indicesFromHostname(entry.hn, '>>');
|
||||
}
|
||||
}
|
||||
|
||||
// Apply scriplets
|
||||
for ( const i of todoIndices ) {
|
||||
if ( tonotdoIndices.has(i) ) { continue; }
|
||||
try { $scriptletName$(...argsList[i]); }
|
||||
catch { }
|
||||
}
|
||||
argsList.length = 0;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
};
|
||||
// End of code to inject
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
uBOL_$scriptletName$();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// End of local scope
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void 0;
|
||||
|
|
|
|||
Loading…
Reference in a new issue