@browserless.io/browserless 2.24.0 → 2.24.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +16 -3
  2. package/build/browsers/index.js +1 -1
  3. package/build/routes/chrome/http/content.post.body.json +8 -8
  4. package/build/routes/chrome/http/pdf.post.body.json +8 -8
  5. package/build/routes/chrome/http/scrape.post.body.json +8 -8
  6. package/build/routes/chrome/http/screenshot.post.body.json +8 -8
  7. package/build/routes/chromium/http/content.post.body.json +8 -8
  8. package/build/routes/chromium/http/pdf.post.body.json +8 -8
  9. package/build/routes/chromium/http/scrape.post.body.json +8 -8
  10. package/build/routes/chromium/http/screenshot.post.body.json +8 -8
  11. package/build/routes/management/http/meta.get.js +3 -1
  12. package/build/shared/utils/performance/main.js +2 -1
  13. package/extensions/ublock/_locales/ar/messages.json +3 -3
  14. package/extensions/ublock/_locales/bg/messages.json +1 -1
  15. package/extensions/ublock/_locales/br_FR/messages.json +2 -2
  16. package/extensions/ublock/_locales/cy/messages.json +11 -11
  17. package/extensions/ublock/_locales/el/messages.json +2 -2
  18. package/extensions/ublock/_locales/hu/messages.json +1 -1
  19. package/extensions/ublock/_locales/id/messages.json +1 -1
  20. package/extensions/ublock/_locales/lv/messages.json +4 -4
  21. package/extensions/ublock/_locales/mk/messages.json +130 -130
  22. package/extensions/ublock/_locales/oc/messages.json +1 -1
  23. package/extensions/ublock/_locales/pt_BR/messages.json +1 -1
  24. package/extensions/ublock/_locales/pt_PT/messages.json +2 -2
  25. package/extensions/ublock/_locales/si/messages.json +100 -100
  26. package/extensions/ublock/_locales/sr/messages.json +4 -4
  27. package/extensions/ublock/_locales/vi/messages.json +19 -19
  28. package/extensions/ublock/_locales/zh_TW/messages.json +28 -28
  29. package/extensions/ublock/assets/assets.json +33 -29
  30. package/extensions/ublock/assets/thirdparties/easylist/easylist.txt +2984 -3287
  31. package/extensions/ublock/assets/thirdparties/easylist/easyprivacy.txt +150 -171
  32. package/extensions/ublock/assets/thirdparties/pgl.yoyo.org/as/serverlist +37 -27
  33. package/extensions/ublock/assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat +802 -888
  34. package/extensions/ublock/assets/thirdparties/urlhaus-filter/urlhaus-filter-online.txt +2355 -2071
  35. package/extensions/ublock/assets/ublock/badlists.txt +9 -1
  36. package/extensions/ublock/assets/ublock/badware.min.txt +354 -243
  37. package/extensions/ublock/assets/ublock/filters.min.txt +5837 -5737
  38. package/extensions/ublock/assets/ublock/privacy.min.txt +151 -38
  39. package/extensions/ublock/assets/ublock/quick-fixes.min.txt +83 -127
  40. package/extensions/ublock/assets/ublock/unbreak.min.txt +66 -50
  41. package/extensions/ublock/css/codemirror.css +4 -0
  42. package/extensions/ublock/document-blocked.html +3 -1
  43. package/extensions/ublock/js/arglist-parser.js +116 -0
  44. package/extensions/ublock/js/background.js +1 -1
  45. package/extensions/ublock/js/logger-ui.js +1 -1
  46. package/extensions/ublock/js/messaging.js +9 -2
  47. package/extensions/ublock/js/pagestore.js +3 -1
  48. package/extensions/ublock/js/redirect-engine.js +3 -1
  49. package/extensions/ublock/{assets/resources/set-attr.js → js/resources/attribute.js} +115 -11
  50. package/extensions/ublock/js/resources/base.js +38 -0
  51. package/extensions/ublock/js/resources/cookie.js +419 -0
  52. package/extensions/ublock/js/resources/href-sanitizer.js +188 -0
  53. package/extensions/ublock/js/resources/localstorage.js +235 -0
  54. package/extensions/ublock/js/resources/parse-replace.js +54 -0
  55. package/extensions/ublock/js/resources/prevent-settimeout.js +236 -0
  56. package/extensions/ublock/js/resources/proxy-apply.js +109 -0
  57. package/extensions/ublock/js/resources/replace-argument.js +120 -0
  58. package/extensions/ublock/{assets → js}/resources/run-at.js +20 -4
  59. package/extensions/ublock/{assets → js}/resources/safe-self.js +5 -4
  60. package/extensions/ublock/{assets → js}/resources/scriptlets.js +90 -1589
  61. package/extensions/ublock/js/resources/set-constant.js +287 -0
  62. package/extensions/ublock/js/resources/shared.js +44 -0
  63. package/extensions/ublock/js/resources/spoof-css.js +163 -0
  64. package/extensions/ublock/js/s14e-serializer.js +2 -1
  65. package/extensions/ublock/js/scriptlet-filtering-core.js +1 -1
  66. package/extensions/ublock/js/scriptlet-filtering.js +1 -31
  67. package/extensions/ublock/js/static-dnr-filtering.js +143 -129
  68. package/extensions/ublock/js/static-filtering-parser.js +27 -117
  69. package/extensions/ublock/js/static-net-filtering.js +53 -141
  70. package/extensions/ublock/js/traffic.js +1 -1
  71. package/extensions/ublock/js/urlskip.js +166 -0
  72. package/extensions/ublock/js/vapi-background-ext.js +38 -14
  73. package/extensions/ublock/manifest.json +1 -1
  74. package/package.json +11 -11
  75. package/src/browsers/index.ts +1 -1
  76. package/src/routes/management/http/meta.get.ts +6 -1
  77. package/src/shared/utils/performance/main.ts +2 -8
  78. package/static/docs/swagger.json +10 -10
  79. package/static/docs/swagger.min.json +9 -9
  80. package/static/function/client.js +119 -18
  81. package/static/function/index.html +119 -18
@@ -90,6 +90,39 @@ const keyFromSelector = selector => {
90
90
 
91
91
  /******************************************************************************/
92
92
 
93
+ function addGenericCosmeticFilter(context, selector, isException) {
94
+ if ( selector === undefined ) { return; }
95
+ if ( selector.length <= 1 ) { return; }
96
+ if ( isException ) {
97
+ if ( context.genericCosmeticExceptions === undefined ) {
98
+ context.genericCosmeticExceptions = new Set();
99
+ }
100
+ context.genericCosmeticExceptions.add(selector);
101
+ return;
102
+ }
103
+ if ( selector.charCodeAt(0) === 0x7B /* '{' */ ) { return; }
104
+ const key = keyFromSelector(selector);
105
+ if ( key === undefined ) {
106
+ if ( context.genericHighCosmeticFilters === undefined ) {
107
+ context.genericHighCosmeticFilters = new Set();
108
+ }
109
+ context.genericHighCosmeticFilters.add(selector);
110
+ return;
111
+ }
112
+ const type = key.charCodeAt(0);
113
+ const hash = hashFromStr(type, key.slice(1));
114
+ if ( context.genericCosmeticFilters === undefined ) {
115
+ context.genericCosmeticFilters = new Map();
116
+ }
117
+ let bucket = context.genericCosmeticFilters.get(hash);
118
+ if ( bucket === undefined ) {
119
+ context.genericCosmeticFilters.set(hash, bucket = []);
120
+ }
121
+ bucket.push(selector);
122
+ }
123
+
124
+ /******************************************************************************/
125
+
93
126
  function addExtendedToDNR(context, parser) {
94
127
  if ( parser.isExtendedFilter() === false ) { return false; }
95
128
 
@@ -195,35 +228,8 @@ function addExtendedToDNR(context, parser) {
195
228
 
196
229
  // Generic cosmetic filtering
197
230
  if ( parser.hasOptions() === false ) {
198
- const { compiled } = parser.result;
199
- if ( compiled === undefined ) { return; }
200
- if ( compiled.length <= 1 ) { return; }
201
- if ( parser.isException() ) {
202
- if ( context.genericCosmeticExceptions === undefined ) {
203
- context.genericCosmeticExceptions = new Set();
204
- }
205
- context.genericCosmeticExceptions.add(compiled);
206
- return;
207
- }
208
- if ( compiled.charCodeAt(0) === 0x7B /* '{' */ ) { return; }
209
- const key = keyFromSelector(compiled);
210
- if ( key === undefined ) {
211
- if ( context.genericHighCosmeticFilters === undefined ) {
212
- context.genericHighCosmeticFilters = new Set();
213
- }
214
- context.genericHighCosmeticFilters.add(compiled);
215
- return;
216
- }
217
- const type = key.charCodeAt(0);
218
- const hash = hashFromStr(type, key.slice(1));
219
- if ( context.genericCosmeticFilters === undefined ) {
220
- context.genericCosmeticFilters = new Map();
221
- }
222
- let bucket = context.genericCosmeticFilters.get(hash);
223
- if ( bucket === undefined ) {
224
- context.genericCosmeticFilters.set(hash, bucket = []);
225
- }
226
- bucket.push(compiled);
231
+ const { compiled, exception } = parser.result;
232
+ addGenericCosmeticFilter(context, compiled, exception);
227
233
  return;
228
234
  }
229
235
 
@@ -234,26 +240,22 @@ function addExtendedToDNR(context, parser) {
234
240
  if ( context.specificCosmeticFilters === undefined ) {
235
241
  context.specificCosmeticFilters = new Map();
236
242
  }
243
+ const { compiled, exception, raw } = parser.result;
244
+ if ( compiled === undefined ) {
245
+ context.specificCosmeticFilters.set(`Invalid filter: ...##${raw}`, {
246
+ rejected: true
247
+ });
248
+ return;
249
+ }
250
+ let details = context.specificCosmeticFilters.get(compiled);
237
251
  for ( const { hn, not, bad } of parser.getExtFilterDomainIterator() ) {
238
252
  if ( bad ) { continue; }
253
+ if ( not && exception ) { continue; }
239
254
  if ( isRegex(hn) ) { continue; }
240
- let { compiled, exception, raw } = parser.result;
241
- if ( exception ) { continue; }
242
- let rejected;
243
- if ( compiled === undefined ) {
244
- rejected = `Invalid filter: ${hn}##${raw}`;
245
- }
246
- if ( rejected ) {
247
- compiled = rejected;
248
- }
249
- let details = context.specificCosmeticFilters.get(compiled);
250
255
  if ( details === undefined ) {
251
- details = {};
252
- if ( rejected ) { details.rejected = true; }
253
- context.specificCosmeticFilters.set(compiled, details);
256
+ context.specificCosmeticFilters.set(compiled, details = {});
254
257
  }
255
- if ( rejected ) { continue; }
256
- if ( not ) {
258
+ if ( exception ) {
257
259
  if ( details.excludeMatches === undefined ) {
258
260
  details.excludeMatches = [];
259
261
  }
@@ -270,6 +272,13 @@ function addExtendedToDNR(context, parser) {
270
272
  }
271
273
  details.matches.push(hn);
272
274
  }
275
+ if ( details === undefined ) { return; }
276
+ if ( exception ) { return; }
277
+ if ( compiled.startsWith('{') ) { return; }
278
+ if ( details.matches === undefined || details.matches.includes('*') ) {
279
+ addGenericCosmeticFilter(context, compiled, false);
280
+ details.matches = undefined;
281
+ }
273
282
  }
274
283
 
275
284
  /******************************************************************************/
@@ -284,6 +293,7 @@ function addToDNR(context, list) {
284
293
  toDNR: true,
285
294
  nativeCssHas: env.includes('native_css_has'),
286
295
  badTypes: [ sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE ],
296
+ trustedSource: list.trustedSource || undefined,
287
297
  });
288
298
  const compiler = staticNetFilteringEngine.createCompiler();
289
299
 
@@ -344,105 +354,109 @@ function addToDNR(context, list) {
344
354
 
345
355
  /******************************************************************************/
346
356
 
347
- function finalizeRuleset(context, network) {
348
- const ruleset = network.ruleset;
357
+ // Merge rules where possible by merging arrays of a specific property.
358
+ //
359
+ // https://github.com/uBlockOrigin/uBOL-home/issues/10#issuecomment-1304822579
360
+ // Do not merge rules which have errors.
349
361
 
350
- // Assign rule ids
351
- const rulesetMap = new Map();
352
- {
353
- let ruleId = 1;
354
- for ( const rule of ruleset ) {
355
- rulesetMap.set(ruleId++, rule);
362
+ function mergeRules(rulesetMap, mergeTarget) {
363
+ const sorter = (_, v) => {
364
+ if ( Array.isArray(v) ) {
365
+ return typeof v[0] === 'string' ? v.sort() : v;
356
366
  }
357
- }
358
- // Merge rules where possible by merging arrays of a specific property.
359
- //
360
- // https://github.com/uBlockOrigin/uBOL-home/issues/10#issuecomment-1304822579
361
- // Do not merge rules which have errors.
362
- const mergeRules = (rulesetMap, mergeTarget) => {
363
- const mergeMap = new Map();
364
- const sorter = (_, v) => {
365
- if ( Array.isArray(v) ) {
366
- return typeof v[0] === 'string' ? v.sort() : v;
367
+ if ( v instanceof Object ) {
368
+ const sorted = {};
369
+ for ( const kk of Object.keys(v).sort() ) {
370
+ sorted[kk] = v[kk];
367
371
  }
372
+ return sorted;
373
+ }
374
+ return v;
375
+ };
376
+ const ruleHasher = (rule, target) => {
377
+ return JSON.stringify(rule, (k, v) => {
378
+ if ( k.startsWith('_') ) { return; }
379
+ if ( k === target ) { return; }
380
+ return sorter(k, v);
381
+ });
382
+ };
383
+ const extractTargetValue = (obj, target) => {
384
+ for ( const [ k, v ] of Object.entries(obj) ) {
385
+ if ( Array.isArray(v) && k === target ) { return v; }
368
386
  if ( v instanceof Object ) {
369
- const sorted = {};
370
- for ( const kk of Object.keys(v).sort() ) {
371
- sorted[kk] = v[kk];
372
- }
373
- return sorted;
387
+ const r = extractTargetValue(v, target);
388
+ if ( r !== undefined ) { return r; }
374
389
  }
375
- return v;
376
- };
377
- const ruleHasher = (rule, target) => {
378
- return JSON.stringify(rule, (k, v) => {
379
- if ( k.startsWith('_') ) { return; }
380
- if ( k === target ) { return; }
381
- return sorter(k, v);
382
- });
383
- };
384
- const extractTargetValue = (obj, target) => {
385
- for ( const [ k, v ] of Object.entries(obj) ) {
386
- if ( Array.isArray(v) && k === target ) { return v; }
387
- if ( v instanceof Object ) {
388
- const r = extractTargetValue(v, target);
389
- if ( r !== undefined ) { return r; }
390
- }
391
- }
392
- };
393
- const extractTargetOwner = (obj, target) => {
394
- for ( const [ k, v ] of Object.entries(obj) ) {
395
- if ( Array.isArray(v) && k === target ) { return obj; }
396
- if ( v instanceof Object ) {
397
- const r = extractTargetOwner(v, target);
398
- if ( r !== undefined ) { return r; }
399
- }
400
- }
401
- };
402
- for ( const [ id, rule ] of rulesetMap ) {
403
- if ( rule._error !== undefined ) { continue; }
404
- const hash = ruleHasher(rule, mergeTarget);
405
- if ( mergeMap.has(hash) === false ) {
406
- mergeMap.set(hash, []);
390
+ }
391
+ };
392
+ const extractTargetOwner = (obj, target) => {
393
+ for ( const [ k, v ] of Object.entries(obj) ) {
394
+ if ( Array.isArray(v) && k === target ) { return obj; }
395
+ if ( v instanceof Object ) {
396
+ const r = extractTargetOwner(v, target);
397
+ if ( r !== undefined ) { return r; }
407
398
  }
408
- mergeMap.get(hash).push(id);
409
399
  }
410
- for ( const ids of mergeMap.values() ) {
411
- if ( ids.length === 1 ) { continue; }
412
- const leftHand = rulesetMap.get(ids[0]);
413
- const leftHandSet = new Set(
414
- extractTargetValue(leftHand, mergeTarget) || []
415
- );
416
- for ( let i = 1; i < ids.length; i++ ) {
417
- const rightHandId = ids[i];
418
- const rightHand = rulesetMap.get(rightHandId);
419
- const rightHandArray = extractTargetValue(rightHand, mergeTarget);
420
- if ( rightHandArray !== undefined ) {
421
- if ( leftHandSet.size !== 0 ) {
422
- for ( const item of rightHandArray ) {
423
- leftHandSet.add(item);
424
- }
400
+ };
401
+ const mergeMap = new Map();
402
+ for ( const [ id, rule ] of rulesetMap ) {
403
+ if ( rule._error !== undefined ) { continue; }
404
+ const hash = ruleHasher(rule, mergeTarget);
405
+ if ( mergeMap.has(hash) === false ) {
406
+ mergeMap.set(hash, []);
407
+ }
408
+ mergeMap.get(hash).push(id);
409
+ }
410
+ for ( const ids of mergeMap.values() ) {
411
+ if ( ids.length === 1 ) { continue; }
412
+ const leftHand = rulesetMap.get(ids[0]);
413
+ const leftHandSet = new Set(
414
+ extractTargetValue(leftHand, mergeTarget) || []
415
+ );
416
+ for ( let i = 1; i < ids.length; i++ ) {
417
+ const rightHandId = ids[i];
418
+ const rightHand = rulesetMap.get(rightHandId);
419
+ const rightHandArray = extractTargetValue(rightHand, mergeTarget);
420
+ if ( rightHandArray !== undefined ) {
421
+ if ( leftHandSet.size !== 0 ) {
422
+ for ( const item of rightHandArray ) {
423
+ leftHandSet.add(item);
425
424
  }
426
- } else {
427
- leftHandSet.clear();
428
425
  }
429
- rulesetMap.delete(rightHandId);
426
+ } else {
427
+ leftHandSet.clear();
430
428
  }
431
- const leftHandOwner = extractTargetOwner(leftHand, mergeTarget);
432
- if ( leftHandSet.size > 1 ) {
433
- //if ( leftHandOwner === undefined ) { debugger; }
434
- leftHandOwner[mergeTarget] = Array.from(leftHandSet).sort();
435
- } else if ( leftHandSet.size === 0 ) {
436
- if ( leftHandOwner !== undefined ) {
437
- leftHandOwner[mergeTarget] = undefined;
438
- }
429
+ rulesetMap.delete(rightHandId);
430
+ }
431
+ const leftHandOwner = extractTargetOwner(leftHand, mergeTarget);
432
+ if ( leftHandSet.size > 1 ) {
433
+ //if ( leftHandOwner === undefined ) { debugger; }
434
+ leftHandOwner[mergeTarget] = Array.from(leftHandSet).sort();
435
+ } else if ( leftHandSet.size === 0 ) {
436
+ if ( leftHandOwner !== undefined ) {
437
+ leftHandOwner[mergeTarget] = undefined;
439
438
  }
440
439
  }
441
- };
440
+ }
441
+ }
442
+
443
+ /******************************************************************************/
444
+
445
+ function finalizeRuleset(context, network) {
446
+ const ruleset = network.ruleset;
447
+
448
+ // Assign rule ids
449
+ const rulesetMap = new Map();
450
+ {
451
+ let ruleId = 1;
452
+ for ( const rule of ruleset ) {
453
+ rulesetMap.set(ruleId++, rule);
454
+ }
455
+ }
442
456
  mergeRules(rulesetMap, 'resourceTypes');
457
+ mergeRules(rulesetMap, 'removeParams');
443
458
  mergeRules(rulesetMap, 'initiatorDomains');
444
459
  mergeRules(rulesetMap, 'requestDomains');
445
- mergeRules(rulesetMap, 'removeParams');
446
460
  mergeRules(rulesetMap, 'responseHeaders');
447
461
 
448
462
  // Patch id
@@ -498,4 +512,4 @@ async function dnrRulesetFromRawLists(lists, options = {}) {
498
512
 
499
513
  /******************************************************************************/
500
514
 
501
- export { dnrRulesetFromRawLists };
515
+ export { dnrRulesetFromRawLists, mergeRules };
@@ -22,6 +22,7 @@
22
22
  /******************************************************************************/
23
23
 
24
24
  import * as cssTree from '../lib/csstree/css-tree.js';
25
+ import { ArglistParser } from './arglist-parser.js';
25
26
  import Regex from '../lib/regexanalyzer/regex.js';
26
27
 
27
28
  /*******************************************************************************
@@ -606,102 +607,6 @@ const exCharCodeAt = (s, i) => {
606
607
 
607
608
  /******************************************************************************/
608
609
 
609
- class ArgListParser {
610
- constructor(separatorChar = ',', mustQuote = false) {
611
- this.separatorChar = this.actualSeparatorChar = separatorChar;
612
- this.separatorCode = this.actualSeparatorCode = separatorChar.charCodeAt(0);
613
- this.mustQuote = mustQuote;
614
- this.quoteBeg = 0; this.quoteEnd = 0;
615
- this.argBeg = 0; this.argEnd = 0;
616
- this.separatorBeg = 0; this.separatorEnd = 0;
617
- this.transform = false;
618
- this.failed = false;
619
- this.reWhitespaceStart = /^\s+/;
620
- this.reWhitespaceEnd = /\s+$/;
621
- this.reOddTrailingEscape = /(?:^|[^\\])(?:\\\\)*\\$/;
622
- this.reTrailingEscapeChars = /\\+$/;
623
- }
624
- nextArg(pattern, beg = 0) {
625
- const len = pattern.length;
626
- this.quoteBeg = beg + this.leftWhitespaceCount(pattern.slice(beg));
627
- this.failed = false;
628
- const qc = pattern.charCodeAt(this.quoteBeg);
629
- if ( qc === 0x22 /* " */ || qc === 0x27 /* ' */ || qc === 0x60 /* ` */ ) {
630
- this.indexOfNextArgSeparator(pattern, qc);
631
- if ( this.argEnd !== len ) {
632
- this.quoteEnd = this.argEnd + 1;
633
- this.separatorBeg = this.separatorEnd = this.quoteEnd;
634
- this.separatorEnd += this.leftWhitespaceCount(pattern.slice(this.quoteEnd));
635
- if ( this.separatorEnd === len ) { return this; }
636
- if ( pattern.charCodeAt(this.separatorEnd) === this.separatorCode ) {
637
- this.separatorEnd += 1;
638
- return this;
639
- }
640
- }
641
- }
642
- this.indexOfNextArgSeparator(pattern, this.separatorCode);
643
- this.separatorBeg = this.separatorEnd = this.argEnd;
644
- if ( this.separatorBeg < len ) {
645
- this.separatorEnd += 1;
646
- }
647
- this.argEnd -= this.rightWhitespaceCount(pattern.slice(0, this.separatorBeg));
648
- this.quoteEnd = this.argEnd;
649
- if ( this.mustQuote ) {
650
- this.failed = true;
651
- }
652
- return this;
653
- }
654
- normalizeArg(s, char = '') {
655
- if ( char === '' ) { char = this.actualSeparatorChar; }
656
- let out = '';
657
- let pos = 0;
658
- while ( (pos = s.lastIndexOf(char)) !== -1 ) {
659
- out = s.slice(pos) + out;
660
- s = s.slice(0, pos);
661
- const match = this.reTrailingEscapeChars.exec(s);
662
- if ( match === null ) { continue; }
663
- const tail = (match[0].length & 1) !== 0
664
- ? match[0].slice(0, -1)
665
- : match[0];
666
- out = tail + out;
667
- s = s.slice(0, -match[0].length);
668
- }
669
- if ( out === '' ) { return s; }
670
- return s + out;
671
- }
672
- leftWhitespaceCount(s) {
673
- const match = this.reWhitespaceStart.exec(s);
674
- return match === null ? 0 : match[0].length;
675
- }
676
- rightWhitespaceCount(s) {
677
- const match = this.reWhitespaceEnd.exec(s);
678
- return match === null ? 0 : match[0].length;
679
- }
680
- indexOfNextArgSeparator(pattern, separatorCode) {
681
- this.argBeg = this.argEnd = separatorCode !== this.separatorCode
682
- ? this.quoteBeg + 1
683
- : this.quoteBeg;
684
- this.transform = false;
685
- if ( separatorCode !== this.actualSeparatorCode ) {
686
- this.actualSeparatorCode = separatorCode;
687
- this.actualSeparatorChar = String.fromCharCode(separatorCode);
688
- }
689
- while ( this.argEnd < pattern.length ) {
690
- const pos = pattern.indexOf(this.actualSeparatorChar, this.argEnd);
691
- if ( pos === -1 ) {
692
- return (this.argEnd = pattern.length);
693
- }
694
- if ( this.reOddTrailingEscape.test(pattern.slice(0, pos)) === false ) {
695
- return (this.argEnd = pos);
696
- }
697
- this.transform = true;
698
- this.argEnd = pos + 1;
699
- }
700
- }
701
- }
702
-
703
- /******************************************************************************/
704
-
705
610
  class AstWalker {
706
611
  constructor(parser, from = 0) {
707
612
  this.parser = parser;
@@ -904,8 +809,8 @@ export class AstFilterParser {
904
809
  this.reBadPP = /(?:^|[;,])\s*report-to\b/i;
905
810
  this.reNetOption = /^(~?)([134a-z_-]+)(=?)/;
906
811
  this.reNoopOption = /^_+$/;
907
- this.netOptionValueParser = new ArgListParser(',');
908
- this.scriptletArgListParser = new ArgListParser(',');
812
+ this.netOptionValueParser = new ArglistParser(',');
813
+ this.scriptletArgListParser = new ArglistParser(',');
909
814
  }
910
815
 
911
816
  finish() {
@@ -1572,18 +1477,15 @@ export class AstFilterParser {
1572
1477
  if ( j === -1 ) { return end; }
1573
1478
  if ( (j+1) === end ) { return end; }
1574
1479
  for (;;) {
1575
- const before = s.charCodeAt(j-1);
1576
- if ( j !== start && before === 0x24 /* $ */ ) { return -1; }
1577
- const after = s.charCodeAt(j+1);
1578
- if (
1579
- after !== 0x29 /* ) */ &&
1580
- after !== 0x2F /* / */ &&
1581
- after !== 0x7C /* | */ &&
1582
- before !== 0x5C /* \ */
1583
- ) {
1584
- return j;
1480
+ const before = s.charAt(j-1);
1481
+ if ( before === '$' ) { return -1; }
1482
+ const after = s.charAt(j+1);
1483
+ if ( ')/|'.includes(after) === false ) {
1484
+ if ( before === '' || '"\'\\`'.includes(before) === false ) {
1485
+ return j;
1486
+ }
1585
1487
  }
1586
- if ( j <= start ) { break; }
1488
+ if ( j === start ) { break; }
1587
1489
  j = s.lastIndexOf('$', j-1);
1588
1490
  if ( j === -1 ) { break; }
1589
1491
  }
@@ -3100,7 +3002,7 @@ export function parseHeaderValue(arg) {
3100
3002
 
3101
3003
  export function parseReplaceValue(s) {
3102
3004
  if ( s.charCodeAt(0) !== 0x2F /* / */ ) { return; }
3103
- const parser = new ArgListParser('/');
3005
+ const parser = new ArglistParser('/');
3104
3006
  parser.nextArg(s, 1);
3105
3007
  let pattern = s.slice(parser.argBeg, parser.argEnd);
3106
3008
  if ( parser.transform ) {
@@ -3345,10 +3247,13 @@ class ExtSelectorCompiler {
3345
3247
  // We have an Adguard/ABP cosmetic filter if and only if the
3346
3248
  // character is `$`, `%` or `?`, otherwise it's not a cosmetic
3347
3249
  // filter.
3348
- // Adguard's style injection: translate to uBO's format.
3349
- if ( compileOptions.adgStyleSyntax === true ) {
3350
- raw = this.translateAdguardCSSInjectionFilter(raw);
3351
- if ( raw === '' ) { return false; }
3250
+ // Adguard/EasyList style injection: translate to uBO's format.
3251
+ if ( this.isStyleInjectionFilter(raw) ) {
3252
+ const translated = this.translateStyleInjectionFilter(raw);
3253
+ if ( translated === undefined ) { return false; }
3254
+ raw = translated;
3255
+ } else if ( compileOptions.adgStyleSyntax === true ) {
3256
+ return false;
3352
3257
  }
3353
3258
 
3354
3259
  // Normalize AdGuard's attribute-based procedural operators.
@@ -3884,9 +3789,14 @@ class ExtSelectorCompiler {
3884
3789
  return true;
3885
3790
  }
3886
3791
 
3887
- translateAdguardCSSInjectionFilter(suffix) {
3888
- const matches = /^(.*)\s*\{([^}]+)\}\s*$/.exec(suffix);
3889
- if ( matches === null ) { return ''; }
3792
+ isStyleInjectionFilter(selector) {
3793
+ const len = selector.length;
3794
+ return len !== 0 && selector.charCodeAt(len-1) === 0x7D /* } */;
3795
+ }
3796
+
3797
+ translateStyleInjectionFilter(raw) {
3798
+ const matches = /^(.+)\s*\{([^}]+)\}$/.exec(raw);
3799
+ if ( matches === null ) { return; }
3890
3800
  const selector = matches[1].trim();
3891
3801
  const style = matches[2].trim();
3892
3802
  // Special style directive `remove: true` is converted into a