Index: lib/matcher.js |
=================================================================== |
--- a/lib/matcher.js |
+++ b/lib/matcher.js |
@@ -21,45 +21,42 @@ |
* @fileOverview Matcher class implementing matching addresses against |
* a list of filters. |
*/ |
const {Filter, WhitelistFilter} = require("./filterClasses"); |
/** |
* Blacklist/whitelist filter matching |
- * @constructor |
*/ |
-function Matcher() |
+class Matcher |
{ |
- this.clear(); |
-} |
-exports.Matcher = Matcher; |
+ constructor() |
+ { |
+ /** |
+ * Lookup table for filters by their associated keyword |
+ * @type {Map.<string,(Filter|Filter[])>} |
+ */ |
+ this.filterByKeyword = new Map(); |
-Matcher.prototype = { |
- /** |
- * Lookup table for filters by their associated keyword |
- * @type {Map.<string,(Filter|Filter[])>} |
- */ |
- filterByKeyword: null, |
- |
- /** |
- * Lookup table for keywords by the filter |
- * @type {Map.<Filter,string>} |
- */ |
- keywordByFilter: null, |
+ /** |
+ * Lookup table for keywords by the filter |
+ * @type {Map.<Filter,string>} |
+ */ |
+ this.keywordByFilter = new Map(); |
+ } |
/** |
* Removes all known filters |
*/ |
clear() |
{ |
- this.filterByKeyword = new Map(); |
- this.keywordByFilter = new Map(); |
- }, |
+ this.filterByKeyword.clear(); |
+ this.keywordByFilter.clear(); |
+ } |
/** |
* Adds a filter to the matcher |
* @param {RegExpFilter} filter |
*/ |
add(filter) |
{ |
if (this.keywordByFilter.has(filter)) |
@@ -70,17 +67,17 @@ |
let oldEntry = this.filterByKeyword.get(keyword); |
if (typeof oldEntry == "undefined") |
this.filterByKeyword.set(keyword, filter); |
else if (oldEntry.length == 1) |
this.filterByKeyword.set(keyword, [oldEntry, filter]); |
else |
oldEntry.push(filter); |
this.keywordByFilter.set(filter, keyword); |
- }, |
+ } |
/** |
* Removes a filter from the matcher |
* @param {RegExpFilter} filter |
*/ |
remove(filter) |
{ |
let keyword = this.keywordByFilter.get(filter); |
@@ -97,22 +94,22 @@ |
{ |
list.splice(index, 1); |
if (list.length == 1) |
this.filterByKeyword.set(keyword, list[0]); |
} |
} |
this.keywordByFilter.delete(filter); |
- }, |
+ } |
/** |
* Chooses a keyword to be associated with the filter |
* @param {Filter} filter |
- * @return {string} keyword or an empty string if no keyword could be found |
+ * @returns {string} keyword or an empty string if no keyword could be found |
*/ |
findKeyword(filter) |
{ |
let result = ""; |
let {text} = filter; |
if (Filter.regexpRegExp.test(text)) |
return result; |
@@ -143,49 +140,49 @@ |
(count == resultCount && candidate.length > resultLength)) |
{ |
result = candidate; |
resultCount = count; |
resultLength = candidate.length; |
} |
} |
return result; |
- }, |
+ } |
/** |
* Checks whether a particular filter is being matched against. |
* @param {RegExpFilter} filter |
- * @return {boolean} |
+ * @returns {boolean} |
*/ |
hasFilter(filter) |
{ |
return this.keywordByFilter.has(filter); |
- }, |
+ } |
/** |
* Returns the keyword used for a filter, null for unknown filters. |
* @param {RegExpFilter} filter |
- * @return {?string} |
+ * @returns {?string} |
*/ |
getKeywordForFilter(filter) |
{ |
let keyword = this.keywordByFilter.get(filter); |
return typeof keyword != "undefined" ? keyword : null; |
- }, |
+ } |
/** |
* Checks whether the entries for a particular keyword match a URL |
* @param {string} keyword |
* @param {string} location |
* @param {number} typeMask |
- * @param {string} docDomain |
- * @param {boolean} thirdParty |
- * @param {string} sitekey |
- * @param {boolean} specificOnly |
- * @return {?Filter} |
+ * @param {string} [docDomain] |
+ * @param {boolean} [thirdParty] |
+ * @param {string} [sitekey] |
+ * @param {boolean} [specificOnly] |
+ * @returns {?Filter} |
*/ |
_checkEntryMatch(keyword, location, typeMask, docDomain, thirdParty, sitekey, |
specificOnly) |
{ |
let list = this.filterByKeyword.get(keyword); |
if (typeof list == "undefined") |
return null; |
for (let i = 0; i < list.length; i++) |
@@ -195,34 +192,34 @@ |
if (specificOnly && filter.isGeneric() && |
!(filter instanceof WhitelistFilter)) |
continue; |
if (filter.matches(location, typeMask, docDomain, thirdParty, sitekey)) |
return filter; |
} |
return null; |
- }, |
+ } |
/** |
* Tests whether the URL matches any of the known filters |
* @param {string} location |
* URL to be tested |
* @param {number} typeMask |
* bitmask of content / request types to match |
- * @param {string} docDomain |
+ * @param {string} [docDomain] |
* domain name of the document that loads the URL |
- * @param {boolean} thirdParty |
+ * @param {boolean} [thirdParty] |
* should be true if the URL is a third-party request |
- * @param {string} sitekey |
+ * @param {string} [sitekey] |
* public key provided by the document |
- * @param {boolean} specificOnly |
- * should be true if generic matches should be ignored |
- * @return {?RegExpFilter} |
- * matching filter or null |
+ * @param {boolean} [specificOnly] |
+ * should be <code>true</code> if generic matches should be ignored |
+ * @returns {?RegExpFilter} |
+ * matching filter or <code>null</code> |
*/ |
matchesAny(location, typeMask, docDomain, thirdParty, sitekey, specificOnly) |
{ |
let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); |
if (candidates === null) |
candidates = []; |
candidates.push(""); |
for (let i = 0, l = candidates.length; i < l; i++) |
@@ -231,146 +228,144 @@ |
docDomain, thirdParty, sitekey, |
specificOnly); |
if (result) |
return result; |
} |
return null; |
} |
-}; |
+} |
+ |
+exports.Matcher = Matcher; |
-/** |
- * Combines a matcher for blocking and exception rules, automatically sorts |
- * rules into two Matcher instances. |
- * @constructor |
- * @augments Matcher |
- */ |
-function CombinedMatcher() |
-{ |
- this.blacklist = new Matcher(); |
- this.whitelist = new Matcher(); |
- this.resultCache = new Map(); |
-} |
-exports.CombinedMatcher = CombinedMatcher; |
+ |
-/** |
- * Maximal number of matching cache entries to be kept |
- * @type {number} |
- */ |
-CombinedMatcher.maxCacheEntries = 1000; |
- |
-CombinedMatcher.prototype = |
+class CombinedMatcher |
{ |
/** |
- * Matcher for blocking rules. |
- * @type {Matcher} |
+ * Combines a matcher for blocking and exception rules, automatically sorts |
+ * rules into two Matcher instances. |
+ * @augments Matcher |
*/ |
- blacklist: null, |
+ constructor() |
+ { |
+ /** |
+ * Maximal number of matching cache entries to be kept |
+ * @type {number} |
+ */ |
+ this.maxCacheEntries = 1000; |
- /** |
- * Matcher for exception rules. |
- * @type {Matcher} |
- */ |
- whitelist: null, |
+ /** |
+ * Matcher for blocking rules. |
+ * @type {Matcher} |
+ */ |
+ this.blacklist = new Matcher(); |
- /** |
- * Lookup table of previous matchesAny results |
- * @type {Map.<string,Filter>} |
- */ |
- resultCache: null, |
+ /** |
+ * Matcher for exception rules. |
+ * @type {Matcher} |
+ */ |
+ this.whitelist = new Matcher(); |
+ |
+ /** |
+ * Lookup table of previous matchesAny results |
+ * @type {Map.<string,Filter>} |
+ */ |
+ this.resultCache = new Map(); |
+ } |
/** |
* @see Matcher#clear |
*/ |
clear() |
{ |
this.blacklist.clear(); |
this.whitelist.clear(); |
this.resultCache.clear(); |
- }, |
+ } |
/** |
* @see Matcher#add |
* @param {Filter} filter |
*/ |
add(filter) |
{ |
if (filter instanceof WhitelistFilter) |
this.whitelist.add(filter); |
else |
this.blacklist.add(filter); |
this.resultCache.clear(); |
- }, |
+ } |
/** |
* @see Matcher#remove |
* @param {Filter} filter |
*/ |
remove(filter) |
{ |
if (filter instanceof WhitelistFilter) |
this.whitelist.remove(filter); |
else |
this.blacklist.remove(filter); |
this.resultCache.clear(); |
- }, |
+ } |
/** |
* @see Matcher#findKeyword |
* @param {Filter} filter |
- * @return {string} keyword |
+ * @returns {string} keyword |
*/ |
findKeyword(filter) |
{ |
if (filter instanceof WhitelistFilter) |
return this.whitelist.findKeyword(filter); |
return this.blacklist.findKeyword(filter); |
- }, |
+ } |
/** |
* @see Matcher#hasFilter |
* @param {Filter} filter |
- * @return {boolean} |
+ * @returns {boolean} |
*/ |
hasFilter(filter) |
{ |
if (filter instanceof WhitelistFilter) |
return this.whitelist.hasFilter(filter); |
return this.blacklist.hasFilter(filter); |
- }, |
+ } |
/** |
* @see Matcher#getKeywordForFilter |
* @param {Filter} filter |
- * @return {string} keyword |
+ * @returns {string} keyword |
*/ |
getKeywordForFilter(filter) |
{ |
if (filter instanceof WhitelistFilter) |
return this.whitelist.getKeywordForFilter(filter); |
return this.blacklist.getKeywordForFilter(filter); |
- }, |
+ } |
/** |
* Checks whether a particular filter is slow |
* @param {RegExpFilter} filter |
- * @return {boolean} |
+ * @returns {boolean} |
*/ |
isSlowFilter(filter) |
{ |
let matcher = ( |
filter instanceof WhitelistFilter ? this.whitelist : this.blacklist |
); |
if (matcher.hasFilter(filter)) |
return !matcher.getKeywordForFilter(filter); |
return !matcher.findKeyword(filter); |
- }, |
+ } |
/** |
* Optimized filter matching testing both whitelist and blacklist matchers |
* simultaneously. For parameters see |
{@link Matcher#matchesAny Matcher.matchesAny()}. |
* @see Matcher#matchesAny |
* @inheritdoc |
*/ |
@@ -395,17 +390,17 @@ |
{ |
blacklistHit = this.blacklist._checkEntryMatch( |
substr, location, typeMask, docDomain, thirdParty, sitekey, |
specificOnly |
); |
} |
} |
return blacklistHit; |
- }, |
+ } |
/** |
* @see Matcher#matchesAny |
* @inheritdoc |
*/ |
matchesAny(location, typeMask, docDomain, thirdParty, sitekey, specificOnly) |
{ |
let key = location + " " + typeMask + " " + docDomain + " " + thirdParty + |
@@ -420,15 +415,17 @@ |
if (this.resultCache.size >= CombinedMatcher.maxCacheEntries) |
this.resultCache.clear(); |
this.resultCache.set(key, result); |
return result; |
} |
-}; |
+} |
+ |
+exports.CombinedMatcher = CombinedMatcher; |
/** |
* Shared CombinedMatcher instance that should usually be used. |
* @type {CombinedMatcher} |
*/ |
exports.defaultMatcher = new CombinedMatcher(); |