| Left: | ||
| Right: |
| LEFT | RIGHT |
|---|---|
| 1 "use strict"; | 1 "use strict"; |
| 2 | 2 |
| 3 let readline = require("readline"); | 3 let readline = require("readline"); |
| 4 let punycode = require("punycode"); | 4 let punycode = require("punycode"); |
| 5 let tldjs = require("tldjs"); | 5 let tldjs = require("tldjs"); |
| 6 let filterClasses = require("./adblockplus.js"); | 6 let filterClasses = require("./adblockplus.js"); |
| 7 | 7 |
| 8 let typeMap = filterClasses.RegExpFilter.typeMap; | 8 let typeMap = filterClasses.RegExpFilter.typeMap; |
| 9 | 9 |
| 10 const selectorLimit = 5000; | 10 const selectorLimit = 5000; |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 247 return true; | 247 return true; |
| 248 | 248 |
| 249 for (let name of Object.getOwnPropertyNames(obj)) | 249 for (let name of Object.getOwnPropertyNames(obj)) |
| 250 if (hasNonASCI(obj[name])) | 250 if (hasNonASCI(obj[name])) |
| 251 return true; | 251 return true; |
| 252 } | 252 } |
| 253 | 253 |
| 254 return false; | 254 return false; |
| 255 } | 255 } |
| 256 | 256 |
| 257 function attributeSyntaxForIDs(selector) | 257 function convertIDSelectorsToAttributeSelectors(selector) |
| 258 { | 258 { |
| 259 if (selector.indexOf("#") == -1) | |
| 260 return selector; | |
| 261 | |
| 262 // First we figure out where all the IDs are | 259 // First we figure out where all the IDs are |
| 263 let sep = ""; | 260 let sep = ""; |
| 264 let IDstart = null; | 261 let start = null; |
| 265 let IDpositions = []; | 262 let positions = []; |
| 266 for (let i = 0; i < selector.length; i++) | 263 for (let i = 0; i < selector.length; i++) |
| 267 { | 264 { |
| 268 let chr = selector[i]; | 265 let chr = selector[i]; |
| 269 | 266 |
| 270 if (chr == "\\") // ignore escaped characters | 267 if (chr == "\\") // ignore escaped characters |
| 271 i++; | 268 i++; |
| 272 else if (chr == sep) // don't split within quoted text | 269 else if (chr == sep) // don't match IDs within quoted text |
| 273 sep = ""; // e.g. [attr=","] | 270 sep = ""; // e.g. [attr="#Hello"] |
| 274 else if (sep == "") | 271 else if (sep == "") |
| 275 { | 272 { |
| 276 if (chr == '"' || chr == "'") | 273 if (chr == '"' || chr == "'") |
| 277 sep = chr; | 274 sep = chr; |
| 278 else if (IDstart == null) // look for the start of an ID | 275 else if (start == null) // look for the start of an ID |
| 279 { | 276 { |
| 280 if (chr == "#") | 277 if (chr == "#") |
| 281 IDstart = i; | 278 start = i; |
| 282 } | 279 } |
| 283 else if (chr < "0" && chr != "-" || | 280 else if (chr != "-" && chr != "_" && |
|
Sebastian Noack
2016/02/17 14:22:19
I'd find the logic here easier to read if you'd ch
kzar
2016/02/17 15:35:03
Done.
| |
| 284 chr > "9" && chr < "A" || | 281 (chr < "0" || |
| 285 chr > "Z" && chr != "_" && chr < "a" || | 282 chr > "9" && chr < "A" || |
| 286 chr > "z" && chr < "\x80") // look for the end of the ID | 283 chr > "Z" && chr < "a" || |
| 284 chr > "z" && chr < "\x80")) // look for the end of the ID | |
| 287 { | 285 { |
| 288 IDpositions.push({start: IDstart, end: i}); | 286 positions.push({start: start, end: i}); |
| 289 IDstart = null; | 287 start = null; |
| 290 } | 288 } |
| 291 } | 289 } |
| 292 } | 290 } |
| 293 | 291 if (start != null) |
| 294 if (IDpositions.length == 0) | 292 positions.push({start: start, end: selector.length}); |
| 295 return selector; | |
| 296 | 293 |
| 297 // Now replace them all with the [id="someID"] form | 294 // Now replace them all with the [id="someID"] form |
| 298 let newSelector = ""; | 295 let newSelector = []; |
| 299 let position = 0; | 296 let i = 0; |
| 300 for (let ID of IDpositions) | 297 for (let pos of positions) |
| 301 { | 298 { |
| 302 newSelector += selector.substring(position, ID.start); | 299 newSelector.push(selector.substring(i, pos.start)); |
| 303 newSelector += '[id="' + selector.substring(ID.start + 1, ID.end) + '"]'; | 300 newSelector.push('[id=' + selector.substring(pos.start + 1, pos.end) + ']'); |
| 304 position = ID.end; | 301 i = pos.end; |
| 305 } | 302 } |
| 306 newSelector += selector.substring(position); | 303 newSelector.push(selector.substring(i)); |
| 307 | 304 |
| 308 return newSelector; | 305 return newSelector.join(""); |
| 309 } | 306 } |
| 310 | 307 |
| 311 function logRules() | 308 function logRules() |
| 312 { | 309 { |
| 313 let rules = []; | 310 let rules = []; |
| 314 | 311 |
| 315 function addRule(rule) | 312 function addRule(rule) |
| 316 { | 313 { |
| 317 if (!hasNonASCI(rule)) | 314 if (!hasNonASCI(rule)) |
| 318 rules.push(rule); | 315 rules.push(rule); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 337 } | 334 } |
| 338 | 335 |
| 339 groupedElemhideFilters.forEach((selectors, matchDomain) => | 336 groupedElemhideFilters.forEach((selectors, matchDomain) => |
| 340 { | 337 { |
| 341 while (selectors.length) | 338 while (selectors.length) |
| 342 { | 339 { |
| 343 let selector = selectors.splice(0, selectorLimit).join(", "); | 340 let selector = selectors.splice(0, selectorLimit).join(", "); |
| 344 | 341 |
| 345 // As of Safari 9.0 element IDs are matched as lowercase. We work around | 342 // As of Safari 9.0 element IDs are matched as lowercase. We work around |
| 346 // this by converting to the attribute format [id="elementID"] | 343 // this by converting to the attribute format [id="elementID"] |
| 347 selector = attributeSyntaxForIDs(selector); | 344 selector = convertIDSelectorsToAttributeSelectors(selector); |
| 348 | 345 |
| 349 addRule({ | 346 addRule({ |
| 350 trigger: {"url-filter": matchDomain}, | 347 trigger: {"url-filter": matchDomain}, |
| 351 action: {type: "css-display-none", | 348 action: {type: "css-display-none", |
| 352 selector: selector} | 349 selector: selector} |
| 353 }); | 350 }); |
| 354 } | 351 } |
| 355 }); | 352 }); |
| 356 | 353 |
| 357 for (let filter of elemhideExceptions) | 354 for (let filter of elemhideExceptions) |
| 358 addRule(convertFilter(filter, "ignore-previous-rules", false)); | 355 addRule(convertFilter(filter, "ignore-previous-rules", false)); |
| 359 | 356 |
| 360 for (let filter of requestFilters) | 357 for (let filter of requestFilters) |
| 361 addRule(convertFilter(filter, "block", true)); | 358 addRule(convertFilter(filter, "block", true)); |
| 362 for (let filter of requestExceptions) | 359 for (let filter of requestExceptions) |
| 363 addRule(convertFilter(filter, "ignore-previous-rules", true)); | 360 addRule(convertFilter(filter, "ignore-previous-rules", true)); |
| 364 | 361 |
| 365 console.log(JSON.stringify(rules, null, "\t")); | 362 console.log(JSON.stringify(rules, null, "\t")); |
| 366 } | 363 } |
| 367 | 364 |
| 368 let rl = readline.createInterface({input: process.stdin, terminal: false}); | 365 let rl = readline.createInterface({input: process.stdin, terminal: false}); |
| 369 rl.on("line", parseFilter); | 366 rl.on("line", parseFilter); |
| 370 rl.on("close", logRules); | 367 rl.on("close", logRules); |
| LEFT | RIGHT |