mirror of https://github.com/gorhill/uBlock.git
[mv3] Various approach to minimize DNR ruleset file
Related issue: https://github.com/mozilla/addons-server/issues/4717
This commit is contained in:
parent
9d696998c7
commit
a9a78d415d
|
@ -249,6 +249,54 @@ const isGood = rule =>
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// Two distinct hostnames:
|
||||||
|
// www.example.com
|
||||||
|
// example.com
|
||||||
|
// Can be reduced to a single one:
|
||||||
|
// example.com
|
||||||
|
// Since if example.com matches, then www.example.com (or any other subdomain
|
||||||
|
// of example.com) will always match.
|
||||||
|
|
||||||
|
function pruneHostnameArray(hostnames) {
|
||||||
|
const rootMap = new Map();
|
||||||
|
for ( const hostname of hostnames ) {
|
||||||
|
const labels = hostname.split('.');
|
||||||
|
let currentMap = rootMap;
|
||||||
|
let i = labels.length;
|
||||||
|
while ( i-- ) {
|
||||||
|
const label = labels[i];
|
||||||
|
let nextMap = currentMap.get(label);
|
||||||
|
if ( nextMap === null ) { break; }
|
||||||
|
if ( nextMap === undefined ) {
|
||||||
|
if ( i === 0 ) {
|
||||||
|
currentMap.set(label, (nextMap = null));
|
||||||
|
} else {
|
||||||
|
currentMap.set(label, (nextMap = new Map()));
|
||||||
|
}
|
||||||
|
} else if ( i === 0 ) {
|
||||||
|
currentMap.set(label, null);
|
||||||
|
}
|
||||||
|
currentMap = nextMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const assemble = (currentMap, currentHostname, out) => {
|
||||||
|
for ( const [ label, nextMap ] of currentMap ) {
|
||||||
|
const nextHostname = currentHostname === ''
|
||||||
|
? label
|
||||||
|
: `${label}.${currentHostname}`;
|
||||||
|
if ( nextMap === null ) {
|
||||||
|
out.push(nextHostname);
|
||||||
|
} else {
|
||||||
|
assemble(nextMap, nextHostname, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
};
|
||||||
|
return assemble(rootMap, '', []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
async function processNetworkFilters(assetDetails, network) {
|
async function processNetworkFilters(assetDetails, network) {
|
||||||
const replacer = (k, v) => {
|
const replacer = (k, v) => {
|
||||||
if ( k.startsWith('_') ) { return; }
|
if ( k.startsWith('_') ) { return; }
|
||||||
|
@ -271,6 +319,37 @@ async function processNetworkFilters(assetDetails, network) {
|
||||||
log(`\tRejected filter count: ${network.rejectedFilterCount}`);
|
log(`\tRejected filter count: ${network.rejectedFilterCount}`);
|
||||||
log(`Output rule count: ${rules.length}`);
|
log(`Output rule count: ${rules.length}`);
|
||||||
|
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/declarativeNetRequest/RuleCondition#browser_compatibility
|
||||||
|
// isUrlFilterCaseSensitive is false by default in Firefox. It will be
|
||||||
|
// false by default in Chromium 118+.
|
||||||
|
if ( platform === 'firefox' ) {
|
||||||
|
for ( const rule of rules ) {
|
||||||
|
if ( rule.condition === undefined ) { continue; }
|
||||||
|
if ( rule.condition.urlFilter === undefined ) {
|
||||||
|
if ( rule.condition.regexFilter === undefined ) { continue; }
|
||||||
|
}
|
||||||
|
if ( rule.condition.isUrlFilterCaseSensitive === undefined ) {
|
||||||
|
rule.condition.isUrlFilterCaseSensitive = true;
|
||||||
|
} else if ( rule.condition.isUrlFilterCaseSensitive === false ) {
|
||||||
|
rule.condition.isUrlFilterCaseSensitive = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minimize requestDomains arrays
|
||||||
|
for ( const rule of rules ) {
|
||||||
|
const condition = rule.condition;
|
||||||
|
if ( condition === undefined ) { continue; }
|
||||||
|
const requestDomains = condition.requestDomains;
|
||||||
|
if ( requestDomains === undefined ) { continue; }
|
||||||
|
const beforeCount = requestDomains.length;
|
||||||
|
condition.requestDomains = pruneHostnameArray(requestDomains);
|
||||||
|
const afterCount = condition.requestDomains.length;
|
||||||
|
if ( afterCount !== beforeCount ) {
|
||||||
|
log(`\tPruning requestDomains: from ${beforeCount} to ${afterCount}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const plainGood = rules.filter(rule => isGood(rule) && isRegex(rule) === false);
|
const plainGood = rules.filter(rule => isGood(rule) && isRegex(rule) === false);
|
||||||
log(`\tPlain good: ${plainGood.length}`);
|
log(`\tPlain good: ${plainGood.length}`);
|
||||||
log(plainGood
|
log(plainGood
|
||||||
|
@ -314,9 +393,11 @@ async function processNetworkFilters(assetDetails, network) {
|
||||||
log(`\tUnsupported: ${bad.length}`);
|
log(`\tUnsupported: ${bad.length}`);
|
||||||
log(bad.map(rule => rule._error.map(v => `\t\t${v}`)).join('\n'), true);
|
log(bad.map(rule => rule._error.map(v => `\t\t${v}`)).join('\n'), true);
|
||||||
|
|
||||||
|
const jsonIndent = platform !== 'firefox' ? 1 : undefined;
|
||||||
|
|
||||||
writeFile(
|
writeFile(
|
||||||
`${rulesetDir}/main/${assetDetails.id}.json`,
|
`${rulesetDir}/main/${assetDetails.id}.json`,
|
||||||
`${JSON.stringify(plainGood, replacer, 1)}\n`
|
`${JSON.stringify(plainGood, replacer, jsonIndent)}\n`
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( regexes.length !== 0 ) {
|
if ( regexes.length !== 0 ) {
|
||||||
|
|
Loading…
Reference in New Issue