Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: lib/matcher.js

Issue 29897555: Issue 6940 - Use underscore prefixes lib/matcher.js (Closed)
Left Patch Set: Rebase Created Oct. 21, 2018, 3:04 a.m.
Right Patch Set: Address PS6 comment Created Oct. 24, 2018, 6:47 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | test/filterListener.js » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-present eyeo GmbH 3 * Copyright (C) 2006-present eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 "use strict"; 18 "use strict";
19 19
20 /** 20 /**
21 * @fileOverview Matcher class implementing matching addresses against 21 * @fileOverview Matcher class implementing matching addresses against
22 * a list of filters. 22 * a list of filters.
23 */ 23 */
24 24
25 const {WhitelistFilter} = require("./filterClasses"); 25 const {RegExpFilter, WhitelistFilter} = require("./filterClasses");
26 26
27 /** 27 /**
28 * Regular expression for matching a keyword in a filter. 28 * Regular expression for matching a keyword in a filter.
29 * @type {RegExp} 29 * @type {RegExp}
30 */ 30 */
31 const keywordRegExp = /[^a-z0-9%*][a-z0-9%]{3,}(?=[^a-z0-9%*])/; 31 const keywordRegExp = /[^a-z0-9%*][a-z0-9%]{3,}(?=[^a-z0-9%*])/;
32 32
33 /** 33 /**
34 * Regular expression for matching all keywords in a filter. 34 * Regular expression for matching all keywords in a filter.
35 * @type {RegExp} 35 * @type {RegExp}
36 */ 36 */
37 const allKeywordsRegExp = new RegExp(keywordRegExp, "g"); 37 const allKeywordsRegExp = new RegExp(keywordRegExp, "g");
38
39 /**
40 * Bitmask for "types" that are for exception rules only, like
41 * <code>$document</code>, <code>$elemhide</code>, and so on.
42 * @type {number}
43 */
44 const WHITELIST_ONLY_TYPES = RegExpFilter.typeMap.DOCUMENT |
45 RegExpFilter.typeMap.ELEMHIDE |
46 RegExpFilter.typeMap.GENERICHIDE |
47 RegExpFilter.typeMap.GENERICBLOCK;
38 48
39 /** 49 /**
40 * Checks whether a particular filter is slow. 50 * Checks whether a particular filter is slow.
41 * @param {RegExpFilter} filter 51 * @param {RegExpFilter} filter
42 * @returns {boolean} 52 * @returns {boolean}
43 */ 53 */
44 function isSlowFilter(filter) 54 function isSlowFilter(filter)
45 { 55 {
46 return !filter.pattern || !keywordRegExp.test(filter.pattern); 56 return !filter.pattern || !keywordRegExp.test(filter.pattern);
47 } 57 }
48 58
49 exports.isSlowFilter = isSlowFilter; 59 exports.isSlowFilter = isSlowFilter;
50 60
51 /** 61 /**
52 * Blacklist/whitelist filter matching 62 * Blacklist/whitelist filter matching
53 */ 63 */
54 class Matcher 64 class Matcher
55 { 65 {
56 constructor() 66 constructor()
57 { 67 {
58 /** 68 /**
59 * Lookup table for filters by their associated keyword 69 * Lookup table for filters by their associated keyword
70 * @type {Map.<string,(Filter|Set.<Filter>)>}
60 * @private 71 * @private
Manish Jethani 2018/10/21 12:12:19 I've already started using @private/@protected els
Jon Sonesen 2018/10/23 01:28:01 Acknowledged.
61 * @type {Map.<string,(Filter|Set.<Filter>)>}
62 */ 72 */
63 this._filterByKeyword = new Map(); 73 this._filterByKeyword = new Map();
64 } 74 }
65 75
66 /** 76 /**
67 * Removes all known filters 77 * Removes all known filters
68 */ 78 */
69 clear() 79 clear()
70 { 80 {
71 this._filterByKeyword.clear(); 81 this._filterByKeyword.clear();
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 { 125 {
116 set.delete(filter); 126 set.delete(filter);
117 127
118 if (set.size == 1) 128 if (set.size == 1)
119 this._filterByKeyword.set(keyword, [...set][0]); 129 this._filterByKeyword.set(keyword, [...set][0]);
120 } 130 }
121 } 131 }
122 132
123 /** 133 /**
124 * Chooses a keyword to be associated with the filter 134 * Chooses a keyword to be associated with the filter
125 * @protected
Manish Jethani 2018/10/21 12:12:19 Same here.
Jon Sonesen 2018/10/23 01:28:04 Acknowledged.
126 * @param {Filter} filter 135 * @param {Filter} filter
127 * @returns {string} keyword or an empty string if no keyword could be found 136 * @returns {string} keyword or an empty string if no keyword could be found
137 * @protected
128 */ 138 */
129 findKeyword(filter) 139 findKeyword(filter)
130 { 140 {
131 let result = ""; 141 let result = "";
132 let {pattern} = filter; 142 let {pattern} = filter;
133 if (pattern == null) 143 if (pattern == null)
134 return result; 144 return result;
135 145
136 let candidates = pattern.toLowerCase().match(allKeywordsRegExp); 146 let candidates = pattern.toLowerCase().match(allKeywordsRegExp);
137 if (!candidates) 147 if (!candidates)
(...skipping 21 matching lines...) Expand all
159 /** 169 /**
160 * Checks whether the entries for a particular keyword match a URL 170 * Checks whether the entries for a particular keyword match a URL
161 * @param {string} keyword 171 * @param {string} keyword
162 * @param {string} location 172 * @param {string} location
163 * @param {number} typeMask 173 * @param {number} typeMask
164 * @param {string} [docDomain] 174 * @param {string} [docDomain]
165 * @param {boolean} [thirdParty] 175 * @param {boolean} [thirdParty]
166 * @param {string} [sitekey] 176 * @param {string} [sitekey]
167 * @param {boolean} [specificOnly] 177 * @param {boolean} [specificOnly]
168 * @returns {?Filter} 178 * @returns {?Filter}
169 */ 179 * @protected
170 _checkEntryMatch(keyword, location, typeMask, docDomain, thirdParty, sitekey, 180 */
Manish Jethani 2018/10/21 12:52:04 About this function, I think we can make it "prote
Jon Sonesen 2018/10/23 01:28:02 Acknowledged.
171 specificOnly) 181 checkEntryMatch(keyword, location, typeMask, docDomain, thirdParty, sitekey,
182 specificOnly)
172 { 183 {
173 let set = this._filterByKeyword.get(keyword); 184 let set = this._filterByKeyword.get(keyword);
174 if (typeof set == "undefined") 185 if (typeof set == "undefined")
175 return null; 186 return null;
176 187
177 for (let filter of set) 188 for (let filter of set)
178 { 189 {
179 if (specificOnly && filter.isGeneric() && 190 if (specificOnly && filter.isGeneric() &&
180 !(filter instanceof WhitelistFilter)) 191 !(filter instanceof WhitelistFilter))
181 continue; 192 continue;
(...skipping 22 matching lines...) Expand all
204 * matching filter or <code>null</code> 215 * matching filter or <code>null</code>
205 */ 216 */
206 matchesAny(location, typeMask, docDomain, thirdParty, sitekey, specificOnly) 217 matchesAny(location, typeMask, docDomain, thirdParty, sitekey, specificOnly)
207 { 218 {
208 let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); 219 let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);
209 if (candidates === null) 220 if (candidates === null)
210 candidates = []; 221 candidates = [];
211 candidates.push(""); 222 candidates.push("");
212 for (let i = 0, l = candidates.length; i < l; i++) 223 for (let i = 0, l = candidates.length; i < l; i++)
213 { 224 {
214 let result = this._checkEntryMatch(candidates[i], location, typeMask, 225 let result = this.checkEntryMatch(candidates[i], location, typeMask,
215 docDomain, thirdParty, sitekey, 226 docDomain, thirdParty, sitekey,
216 specificOnly); 227 specificOnly);
217 if (result) 228 if (result)
218 return result; 229 return result;
219 } 230 }
220 231
221 return null; 232 return null;
222 } 233 }
223 } 234 }
224 235
225 exports.Matcher = Matcher; 236 exports.Matcher = Matcher;
226 237
227 /** 238 /**
228 * Combines a matcher for blocking and exception rules, automatically sorts 239 * Combines a matcher for blocking and exception rules, automatically sorts
229 * rules into two {@link Matcher} instances. 240 * rules into two {@link Matcher} instances.
230 */ 241 */
231 class CombinedMatcher 242 class CombinedMatcher
232 { 243 {
233 constructor() 244 constructor()
234 { 245 {
235 /** 246 /**
236 * Maximal number of matching cache entries to be kept 247 * Maximal number of matching cache entries to be kept
237 * @type {number} 248 * @type {number}
238 */ 249 */
239 this.maxCacheEntries = 1000; 250 this.maxCacheEntries = 1000;
240 251
241 /** 252 /**
242 * Matcher for blocking rules. 253 * Matcher for blocking rules.
243 * @type {Matcher} 254 * @type {Matcher}
255 * @private
244 */ 256 */
245 this.blacklist = new Matcher(); 257 this._blacklist = new Matcher();
246 258
247 /** 259 /**
248 * Matcher for exception rules. 260 * Matcher for exception rules.
249 * @type {Matcher} 261 * @type {Matcher}
262 * @private
250 */ 263 */
251 this.whitelist = new Matcher(); 264 this._whitelist = new Matcher();
252 265
253 /** 266 /**
254 * Lookup table of previous {@link Matcher#matchesAny} results 267 * Lookup table of previous {@link Matcher#matchesAny} results
255 * @type {Map.<string,Filter>} 268 * @type {Map.<string,Filter>}
269 * @private
256 */ 270 */
257 this.resultCache = new Map(); 271 this._resultCache = new Map();
Manish Jethani 2018/10/21 12:52:04 Let's do this entire file while we're at it. I don
Manish Jethani 2018/10/22 22:57:50 FYI we're having a discussion [1] about making bla
Jon Sonesen 2018/10/23 01:28:02 Acknowledged. In the new patch set, I made them pr
Manish Jethani 2018/10/23 03:10:14 I don't think that has anything to do with the cha
Jon Sonesen 2018/10/23 03:16:42 It does, have you tested making them private? I ca
Manish Jethani 2018/10/23 03:23:17 You'll have to modify the tests of course, so they
Manish Jethani 2018/10/23 03:28:42 Please try just changing this line: https://hg.ad
Jon Sonesen 2018/10/23 04:08:03 Yeah I am the worst, thanks for your help and pati
Manish Jethani 2018/10/23 10:38:26 Not at all, it happens to me too :)
258 } 272 }
259 273
260 /** 274 /**
261 * @see Matcher#clear 275 * @see Matcher#clear
262 */ 276 */
263 clear() 277 clear()
264 { 278 {
265 this.blacklist.clear(); 279 this._blacklist.clear();
266 this.whitelist.clear(); 280 this._whitelist.clear();
267 this.resultCache.clear(); 281 this._resultCache.clear();
268 } 282 }
269 283
270 /** 284 /**
271 * @see Matcher#add 285 * @see Matcher#add
272 * @param {Filter} filter 286 * @param {Filter} filter
273 */ 287 */
274 add(filter) 288 add(filter)
275 { 289 {
276 if (filter instanceof WhitelistFilter) 290 if (filter instanceof WhitelistFilter)
277 this.whitelist.add(filter); 291 this._whitelist.add(filter);
278 else 292 else
279 this.blacklist.add(filter); 293 this._blacklist.add(filter);
280 294
281 this.resultCache.clear(); 295 this._resultCache.clear();
282 } 296 }
283 297
284 /** 298 /**
285 * @see Matcher#remove 299 * @see Matcher#remove
286 * @param {Filter} filter 300 * @param {Filter} filter
287 */ 301 */
288 remove(filter) 302 remove(filter)
289 { 303 {
290 if (filter instanceof WhitelistFilter) 304 if (filter instanceof WhitelistFilter)
291 this.whitelist.remove(filter); 305 this._whitelist.remove(filter);
292 else 306 else
293 this.blacklist.remove(filter); 307 this._blacklist.remove(filter);
294 308
295 this.resultCache.clear(); 309 this._resultCache.clear();
296 } 310 }
297 311
298 /** 312 /**
299 * @see Matcher#findKeyword 313 * @see Matcher#findKeyword
300 * @param {Filter} filter 314 * @param {Filter} filter
301 * @returns {string} keyword 315 * @returns {string} keyword
316 * @protected
302 */ 317 */
303 findKeyword(filter) 318 findKeyword(filter)
Manish Jethani 2018/10/21 12:52:03 If we're marking fineKeyword @protected in Matcher
Jon Sonesen 2018/10/23 01:28:04 Done.
304 { 319 {
305 if (filter instanceof WhitelistFilter) 320 if (filter instanceof WhitelistFilter)
306 return this.whitelist.findKeyword(filter); 321 return this._whitelist.findKeyword(filter);
307 return this.blacklist.findKeyword(filter); 322 return this._blacklist.findKeyword(filter);
308 } 323 }
309 324
310 /** 325 /**
311 * Optimized filter matching testing both whitelist and blacklist matchers 326 * Optimized filter matching testing both whitelist and blacklist matchers
312 * simultaneously. For parameters see 327 * simultaneously. For parameters see
313 {@link Matcher#matchesAny Matcher.matchesAny()}. 328 {@link Matcher#matchesAny Matcher.matchesAny()}.
314 * @see Matcher#matchesAny 329 * @see Matcher#matchesAny
315 * @inheritdoc 330 * @inheritdoc
316 */ 331 * @private
317 matchesAnyInternal(location, typeMask, docDomain, thirdParty, sitekey, 332 */
Manish Jethani 2018/10/21 12:52:03 Let's make this private (underscore and @private).
Jon Sonesen 2018/10/23 01:28:02 Acknowledged.
318 specificOnly) 333 _matchesAnyInternal(location, typeMask, docDomain, thirdParty, sitekey,
334 specificOnly)
319 { 335 {
320 let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); 336 let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);
321 if (candidates === null) 337 if (candidates === null)
322 candidates = []; 338 candidates = [];
323 candidates.push(""); 339 candidates.push("");
324 340
341 let whitelistHit = null;
325 let blacklistHit = null; 342 let blacklistHit = null;
326 for (let i = 0, l = candidates.length; i < l; i++) 343
327 { 344 // If the type mask includes no types other than whitelist-only types, we
328 let substr = candidates[i]; 345 // can skip the blacklist.
329 let result = this.whitelist._checkEntryMatch( 346 if ((typeMask & ~WHITELIST_ONLY_TYPES) != 0)
330 substr, location, typeMask, docDomain, thirdParty, sitekey 347 {
331 ); 348 for (let i = 0, l = candidates.length; !blacklistHit && i < l; i++)
332 if (result)
333 return result;
334 if (blacklistHit === null)
335 { 349 {
336 blacklistHit = this.blacklist._checkEntryMatch( 350 blacklistHit = this._blacklist.checkEntryMatch(candidates[i], location,
337 substr, location, typeMask, docDomain, thirdParty, sitekey, 351 typeMask, docDomain,
338 specificOnly 352 thirdParty, sitekey,
339 ); 353 specificOnly);
340 } 354 }
341 } 355 }
342 return blacklistHit; 356
357 // If the type mask includes any whitelist-only types, we need to check the
358 // whitelist.
359 if (blacklistHit || (typeMask & WHITELIST_ONLY_TYPES) != 0)
360 {
361 for (let i = 0, l = candidates.length; !whitelistHit && i < l; i++)
362 {
363 whitelistHit = this._whitelist.checkEntryMatch(candidates[i], location,
364 typeMask, docDomain,
365 thirdParty, sitekey);
366 }
367 }
368
369 return whitelistHit || blacklistHit;
343 } 370 }
344 371
345 /** 372 /**
346 * @see Matcher#matchesAny 373 * @see Matcher#matchesAny
347 * @inheritdoc 374 * @inheritdoc
Manish Jethani 2018/10/21 12:52:04 There are two instances of @inheritdoc in this fil
Jon Sonesen 2018/10/23 01:28:01 Doing this makes eslint throw errors for the valid
Manish Jethani 2018/10/23 03:10:14 Oh yeah, I think you had mentioned this earlier as
348 */ 375 */
349 matchesAny(location, typeMask, docDomain, thirdParty, sitekey, specificOnly) 376 matchesAny(location, typeMask, docDomain, thirdParty, sitekey, specificOnly)
350 { 377 {
351 let key = location + " " + typeMask + " " + docDomain + " " + thirdParty + 378 let key = location + " " + typeMask + " " + docDomain + " " + thirdParty +
352 " " + sitekey + " " + specificOnly; 379 " " + sitekey + " " + specificOnly;
353 380
354 let result = this.resultCache.get(key); 381 let result = this._resultCache.get(key);
355 if (typeof result != "undefined") 382 if (typeof result != "undefined")
356 return result; 383 return result;
357 384
358 result = this.matchesAnyInternal(location, typeMask, docDomain, 385 result = this._matchesAnyInternal(location, typeMask, docDomain,
359 thirdParty, sitekey, specificOnly); 386 thirdParty, sitekey, specificOnly);
360 387
361 if (this.resultCache.size >= this.maxCacheEntries) 388 if (this._resultCache.size >= this.maxCacheEntries)
362 this.resultCache.clear(); 389 this._resultCache.clear();
363 390
364 this.resultCache.set(key, result); 391 this._resultCache.set(key, result);
365 392
366 return result; 393 return result;
367 } 394 }
368 } 395 }
369 396
370 exports.CombinedMatcher = CombinedMatcher; 397 exports.CombinedMatcher = CombinedMatcher;
371 398
372 /** 399 /**
373 * Shared {@link CombinedMatcher} instance that should usually be used. 400 * Shared {@link CombinedMatcher} instance that should usually be used.
374 * @type {CombinedMatcher} 401 * @type {CombinedMatcher}
375 */ 402 */
376 let defaultMatcher = new CombinedMatcher(); 403 let defaultMatcher = new CombinedMatcher();
377 404
378 exports.defaultMatcher = defaultMatcher; 405 exports.defaultMatcher = defaultMatcher;
LEFTRIGHT

Powered by Google App Engine
This is Rietveld