| Index: lib/abp2blocklist.js | 
| =================================================================== | 
| --- a/lib/abp2blocklist.js | 
| +++ b/lib/abp2blocklist.js | 
| @@ -209,17 +209,18 @@ | 
| typeMap.OTHER)) | 
| types.push("raw"); | 
| if (filter.contentType & typeMap.SUBDOCUMENT) | 
| types.push("document"); | 
| return types; | 
| } | 
| -function convertFilterAddRules(rules, filter, action, withResourceTypes) | 
| +function convertFilterAddRules(rules, filter, action, withResourceTypes, | 
| + exceptionDomains) | 
| { | 
| let parsed = parseFilterRegexpSource(filter.regexpSource); | 
| // For the special case of $document whitelisting filters with just a domain | 
| // we can generate an equivalent blocking rule exception using if-domain. | 
| if (filter instanceof filterClasses.WhitelistFilter && | 
| filter.contentType & typeMap.DOCUMENT && | 
| parsed.justHostname) | 
| @@ -251,16 +252,19 @@ | 
| if (parsed.canSafelyMatchAsLowercase || filter.matchCase) | 
| trigger["url-filter-is-case-sensitive"] = true; | 
| let included = []; | 
| let excluded = []; | 
| parseDomains(filter.domains, included, excluded); | 
| + if (exceptionDomains) | 
| + excluded = excluded.concat(exceptionDomains); | 
| + | 
| if (withResourceTypes) | 
| { | 
| trigger["resource-type"] = getResourceTypes(filter); | 
| if (trigger["resource-type"].length == 0) | 
| return; | 
| } | 
| @@ -376,16 +380,17 @@ | 
| * @constructor | 
| */ | 
| exports.ContentBlockerList = function () | 
| { | 
| this.requestFilters = []; | 
| this.requestExceptions = []; | 
| this.elemhideFilters = []; | 
| this.elemhideExceptions = []; | 
| + this.genericblockExceptions = []; | 
| this.generichideExceptions = []; | 
| this.elemhideSelectorExceptions = new Map(); | 
| }; | 
| /** | 
| * Add Adblock Plus filter to be converted | 
| * | 
| * @param {Filter} filter Filter to convert | 
| @@ -401,16 +406,19 @@ | 
| if (filter instanceof filterClasses.BlockingFilter) | 
| this.requestFilters.push(filter); | 
| if (filter instanceof filterClasses.WhitelistFilter) | 
| { | 
| if (filter.contentType & (typeMap.DOCUMENT | whitelistableRequestTypes)) | 
| this.requestExceptions.push(filter); | 
| + if (filter.contentType & typeMap.GENERICBLOCK) | 
| + this.genericblockExceptions.push(filter); | 
| + | 
| if (filter.contentType & typeMap.ELEMHIDE) | 
| this.elemhideExceptions.push(filter); | 
| else if (filter.contentType & typeMap.GENERICHIDE) | 
| this.generichideExceptions.push(filter); | 
| } | 
| if (filter instanceof filterClasses.ElemHideFilter) | 
| this.elemhideFilters.push(filter); | 
| @@ -467,15 +475,28 @@ | 
| groupedElemhideFilters.forEach((selectors, matchDomain) => | 
| { | 
| addCSSRules(rules, selectors, matchDomain); | 
| }); | 
| for (let filter of this.elemhideExceptions) | 
| convertFilterAddRules(rules, filter, "ignore-previous-rules", false); | 
| + | 
| + let requestFilterExceptionDomains = []; | 
| + for (let filter of this.genericblockExceptions) | 
| + { | 
| + let parsed = parseFilterRegexpSource(filter.regexpSource); | 
| + if (parsed.hostname) | 
| + requestFilterExceptionDomains.push(parsed.hostname); | 
| + } | 
| + | 
| for (let filter of this.requestFilters) | 
| - convertFilterAddRules(rules, filter, "block", true); | 
| + { | 
| + convertFilterAddRules(rules, filter, "block", true, | 
| + requestFilterExceptionDomains); | 
| + } | 
| + | 
| for (let filter of this.requestExceptions) | 
| convertFilterAddRules(rules, filter, "ignore-previous-rules", true); | 
| return rules.filter(rule => !hasNonASCI(rule)); | 
| }; |