@adguard/agtree 2.1.3 → 2.2.0

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.
package/dist/agtree.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- * AGTree v2.1.3 (build date: Mon, 21 Oct 2024 08:22:25 GMT)
2
+ * AGTree v2.2.0 (build date: Wed, 27 Nov 2024 16:28:27 GMT)
3
3
  * (c) 2024 Adguard Software Ltd.
4
4
  * Released under the MIT license
5
5
  * https://github.com/AdguardTeam/tsurlfilter/tree/master/packages/agtree#readme
@@ -2357,9 +2357,11 @@ declare class FilterListParser extends ParserBase {
2357
2357
  * @param ast AST to generate
2358
2358
  * @param preferRaw If `true`, then the parser will use `raws.text` property of each rule
2359
2359
  * if it is available. Default is `false`.
2360
+ * @param tolerant If `true`, errors during rule generation will be logged to the console and invalid rules
2361
+ * will be skipped. If `false`, an error will be thrown on the first invalid rule. Default is `true`.
2360
2362
  * @returns Serialized filter list
2361
2363
  */
2362
- static generate(ast: FilterList, preferRaw?: boolean): string;
2364
+ static generate(ast: FilterList, preferRaw?: boolean, tolerant?: boolean): string;
2363
2365
  /**
2364
2366
  * Serializes a filter list node to binary format.
2365
2367
  *
@@ -3697,6 +3699,7 @@ declare const modifierDataSchema: zod.ZodEffects<zod.ZodTypeAny, {
3697
3699
  exceptionOnly: boolean;
3698
3700
  valueOptional: boolean;
3699
3701
  valueFormat: string | null;
3702
+ valueFormatFlags: string | null;
3700
3703
  }, any>;
3701
3704
  /**
3702
3705
  * Type of the modifier data schema.
package/dist/agtree.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- * AGTree v2.1.3 (build date: Mon, 21 Oct 2024 08:22:25 GMT)
2
+ * AGTree v2.2.0 (build date: Wed, 27 Nov 2024 16:28:27 GMT)
3
3
  * (c) 2024 Adguard Software Ltd.
4
4
  * Released under the MIT license
5
5
  * https://github.com/AdguardTeam/tsurlfilter/tree/master/packages/agtree#readme
@@ -13,7 +13,6 @@ var sprintfJs = require('sprintf-js');
13
13
  var cssTokenizer = require('@adguard/css-tokenizer');
14
14
  var tldts = require('tldts');
15
15
  var isIp = require('is-ip');
16
- var XRegExp = require('xregexp');
17
16
  var cloneDeep = require('clone-deep');
18
17
  var compatibilityTableData_js = require('./compatibility-table-data.js');
19
18
  var zod = require('zod');
@@ -1913,6 +1912,9 @@ class AgentCommentRuleParser extends ParserBase {
1913
1912
  static serialize(node, buffer) {
1914
1913
  buffer.writeUint8(BinaryTypeMap.AgentRuleNode);
1915
1914
  const count = node.children.length;
1915
+ // If there are no children, we do not write any data related to them, to avoid using unnecessary storage,
1916
+ // but children is a required field, so during deserialization we should initialize it as an empty array,
1917
+ // if there are no children in the binary data.
1916
1918
  if (count) {
1917
1919
  buffer.writeUint8(AgentRuleSerializationMap.Children);
1918
1920
  // note: we store the count, because re-construction of the array is faster if we know the length
@@ -1967,6 +1969,11 @@ class AgentCommentRuleParser extends ParserBase {
1967
1969
  }
1968
1970
  prop = buffer.readUint8();
1969
1971
  }
1972
+ // Maybe children are not present in the binary data,
1973
+ // in this case, we should initialize it as an empty array.
1974
+ if (!node.children) {
1975
+ node.children = [];
1976
+ }
1970
1977
  }
1971
1978
  }
1972
1979
 
@@ -2862,6 +2869,9 @@ class HintCommentRuleParser extends ParserBase {
2862
2869
  buffer.writeUint8(SYNTAX_SERIALIZATION_MAP.get(exports.AdblockSyntax.Adg) ?? 0);
2863
2870
  }
2864
2871
  const count = node.children.length;
2872
+ // If there are no children, we do not write any data related to them, to avoid using unnecessary storage,
2873
+ // but children is a required field, so during deserialization we should initialize it as an empty array,
2874
+ // if there are no children in the binary data.
2865
2875
  if (count) {
2866
2876
  buffer.writeUint8(HintRuleSerializationMap.Children);
2867
2877
  // note: we store the count, because re-construction of the array is faster if we know the length
@@ -2915,6 +2925,11 @@ class HintCommentRuleParser extends ParserBase {
2915
2925
  }
2916
2926
  prop = buffer.readUint8();
2917
2927
  }
2928
+ // Maybe children are not present in the binary data,
2929
+ // in this case, we should initialize it as an empty array.
2930
+ if (!node.children) {
2931
+ node.children = [];
2932
+ }
2918
2933
  }
2919
2934
  }
2920
2935
 
@@ -5348,6 +5363,9 @@ class ModifierListParser extends ParserBase {
5348
5363
  static serialize(node, buffer) {
5349
5364
  buffer.writeUint8(BinaryTypeMap.ModifierListNode);
5350
5365
  const count = node.children.length;
5366
+ // If there are no children, we do not write any data related to them, to avoid using unnecessary storage,
5367
+ // but children is a required field, so during deserialization we should initialize it as an empty array,
5368
+ // if there are no children in the binary data.
5351
5369
  if (count) {
5352
5370
  buffer.writeUint8(ModifierListNodeSerializationMap.Children);
5353
5371
  // note: we store the count, because re-construction of the array is faster if we know the length
@@ -5399,6 +5417,11 @@ class ModifierListParser extends ParserBase {
5399
5417
  }
5400
5418
  prop = buffer.readUint8();
5401
5419
  }
5420
+ // Maybe children are not present in the binary data,
5421
+ // in this case, we should initialize it as an empty array.
5422
+ if (!node.children) {
5423
+ node.children = [];
5424
+ }
5402
5425
  }
5403
5426
  }
5404
5427
 
@@ -8611,10 +8634,16 @@ class NetworkRuleParser extends ParserBase {
8611
8634
  const pattern = ValueParser.parse(raw.slice(patternStart, patternEnd), options, baseOffset + patternStart);
8612
8635
  // Parse modifiers (if any)
8613
8636
  let modifiers;
8637
+ // Get a last non-whitespace index
8638
+ const lastNonWsIndex = StringUtils.skipWSBack(raw);
8614
8639
  // Find start and end index of the modifiers
8615
8640
  const modifiersStart = separatorIndex + 1;
8616
- const modifiersEnd = StringUtils.skipWSBack(raw) + 1;
8641
+ const modifiersEnd = lastNonWsIndex + 1;
8617
8642
  if (separatorIndex !== -1) {
8643
+ // Check for empty modifiers
8644
+ if (separatorIndex === lastNonWsIndex) {
8645
+ throw new AdblockSyntaxError('Empty modifiers are not allowed', baseOffset + separatorIndex, baseOffset + raw.length);
8646
+ }
8618
8647
  modifiers = ModifierListParser.parse(raw.slice(modifiersStart, modifiersEnd), options, baseOffset + modifiersStart);
8619
8648
  }
8620
8649
  // Throw error if there is no pattern and no modifiers
@@ -8933,6 +8962,9 @@ class HostRuleParser extends ParserBase {
8933
8962
  buffer.writeUint32(node.end);
8934
8963
  }
8935
8964
  const count = node.children.length;
8965
+ // If there are no children, we do not write any data related to them, to avoid using unnecessary storage,
8966
+ // but children is a required field, so during deserialization we should initialize it as an empty array,
8967
+ // if there are no children in the binary data.
8936
8968
  if (count) {
8937
8969
  // note: we store the count, because re-construction of the array is faster if we know the length
8938
8970
  if (count > UINT16_MAX) {
@@ -8976,6 +9008,11 @@ class HostRuleParser extends ParserBase {
8976
9008
  }
8977
9009
  prop = buffer.readUint8();
8978
9010
  }
9011
+ // Maybe children are not present in the binary data,
9012
+ // in this case, we should initialize it as an empty array.
9013
+ if (!node.children) {
9014
+ node.children = [];
9015
+ }
8979
9016
  }
8980
9017
  /**
8981
9018
  * Serializes a host rule node to binary format.
@@ -9743,9 +9780,11 @@ class FilterListParser extends ParserBase {
9743
9780
  * @param ast AST to generate
9744
9781
  * @param preferRaw If `true`, then the parser will use `raws.text` property of each rule
9745
9782
  * if it is available. Default is `false`.
9783
+ * @param tolerant If `true`, errors during rule generation will be logged to the console and invalid rules
9784
+ * will be skipped. If `false`, an error will be thrown on the first invalid rule. Default is `true`.
9746
9785
  * @returns Serialized filter list
9747
9786
  */
9748
- static generate(ast, preferRaw = false) {
9787
+ static generate(ast, preferRaw = false, tolerant = true) {
9749
9788
  let result = EMPTY;
9750
9789
  for (let i = 0; i < ast.children.length; i += 1) {
9751
9790
  const rule = ast.children[i];
@@ -9753,7 +9792,18 @@ class FilterListParser extends ParserBase {
9753
9792
  result += rule.raws.text;
9754
9793
  }
9755
9794
  else {
9756
- result += RuleParser.generate(rule);
9795
+ try {
9796
+ result += RuleParser.generate(rule);
9797
+ }
9798
+ catch (error) {
9799
+ if (tolerant) {
9800
+ // eslint-disable-next-line no-console
9801
+ console.error(`Error when generating: ${error}`);
9802
+ }
9803
+ else {
9804
+ throw new Error(String(error));
9805
+ }
9806
+ }
9757
9807
  }
9758
9808
  switch (rule.raws?.nl) {
9759
9809
  case 'crlf':
@@ -10713,10 +10763,11 @@ const isCustomValueFormatValidator = (valueFormat) => {
10713
10763
  *
10714
10764
  * @param modifier Modifier AST node.
10715
10765
  * @param valueFormat Value format for the modifier.
10766
+ * @param valueFormatFlags Optional; RegExp flags for the value format.
10716
10767
  *
10717
10768
  * @returns Validation result.
10718
10769
  */
10719
- const validateValue = (modifier, valueFormat) => {
10770
+ const validateValue = (modifier, valueFormat, valueFormatFlags) => {
10720
10771
  if (isCustomValueFormatValidator(valueFormat)) {
10721
10772
  const validator = CUSTOM_VALUE_FORMAT_MAP[valueFormat];
10722
10773
  return validator(modifier);
@@ -10725,14 +10776,19 @@ const validateValue = (modifier, valueFormat) => {
10725
10776
  if (!modifier.value?.value) {
10726
10777
  return getValueRequiredValidationResult(modifierName);
10727
10778
  }
10728
- let xRegExp;
10779
+ let regExp;
10729
10780
  try {
10730
- xRegExp = XRegExp(valueFormat);
10781
+ if (isString(valueFormatFlags)) {
10782
+ regExp = new RegExp(valueFormat, valueFormatFlags);
10783
+ }
10784
+ else {
10785
+ regExp = new RegExp(valueFormat);
10786
+ }
10731
10787
  }
10732
10788
  catch (e) {
10733
10789
  throw new Error(`${SOURCE_DATA_ERROR_PREFIX.INVALID_VALUE_FORMAT_REGEXP}: '${modifierName}'`);
10734
10790
  }
10735
- const isValid = xRegExp.test(modifier.value?.value);
10791
+ const isValid = regExp.test(modifier.value?.value);
10736
10792
  if (!isValid) {
10737
10793
  return getInvalidValidationResult(`${VALIDATION_ERROR_PREFIX.VALUE_INVALID}: '${modifierName}'`);
10738
10794
  }
@@ -11316,7 +11372,7 @@ const validateForSpecificSyntax = (syntax, modifier, isException) => {
11316
11372
  if (!specificBlockerData.valueFormat) {
11317
11373
  throw new Error(`${SOURCE_DATA_ERROR_PREFIX.NO_VALUE_FORMAT_FOR_ASSIGNABLE}: '${modifierName}'`);
11318
11374
  }
11319
- return validateValue(modifier, specificBlockerData.valueFormat);
11375
+ return validateValue(modifier, specificBlockerData.valueFormat, specificBlockerData.valueFormatFlags);
11320
11376
  }
11321
11377
  if (modifier?.value) {
11322
11378
  // e.g. 'third-party=true'
@@ -13013,8 +13069,14 @@ function getErrorMessage(error) {
13013
13069
  * Known validators that don't need to be validated as regex.
13014
13070
  */
13015
13071
  const KNOWN_VALIDATORS = new Set([
13072
+ 'csp_value',
13016
13073
  'domain',
13074
+ 'permissions_value',
13075
+ 'pipe_separated_apps',
13076
+ 'pipe_separated_denyallow_domains',
13017
13077
  'pipe_separated_domains',
13078
+ 'pipe_separated_methods',
13079
+ 'pipe_separated_stealth_options',
13018
13080
  'regexp',
13019
13081
  'url',
13020
13082
  ]);
@@ -13065,6 +13127,10 @@ zodToCamelCase(baseCompatibilityDataSchema.extend({
13065
13127
  * Its value can be a regex pattern or a known validator name (e.g. `domain`, `pipe_separated_domains`, etc.).
13066
13128
  */
13067
13129
  value_format: nonEmptyStringSchema.nullable().default(null),
13130
+ /**
13131
+ * Describes the flags for the `value_format` regex pattern.
13132
+ */
13133
+ value_format_flags: nonEmptyStringSchema.nullable().default(null),
13068
13134
  }).superRefine((data, ctx) => {
13069
13135
  // TODO: find something better, for now we can't add refine logic to the base schema:
13070
13136
  // https://github.com/colinhacks/zod/issues/454#issuecomment-848370721
@@ -13085,11 +13151,17 @@ zodToCamelCase(baseCompatibilityDataSchema.extend({
13085
13151
  const valueFormat = data.value_format.trim();
13086
13152
  // if it is a known validator, we don't need to validate it further
13087
13153
  if (KNOWN_VALIDATORS.has(valueFormat)) {
13154
+ if (data.value_format_flags) {
13155
+ ctx.addIssue({
13156
+ code: zod.ZodIssueCode.custom,
13157
+ message: 'value_format_flags are not allowed for known validators',
13158
+ });
13159
+ }
13088
13160
  return;
13089
13161
  }
13090
13162
  // otherwise, we need to validate it as a regex
13091
13163
  try {
13092
- XRegExp(valueFormat);
13164
+ new RegExp(valueFormat, data.value_format_flags ?? EMPTY);
13093
13165
  }
13094
13166
  catch (error) {
13095
13167
  ctx.addIssue({
@@ -13098,6 +13170,12 @@ zodToCamelCase(baseCompatibilityDataSchema.extend({
13098
13170
  });
13099
13171
  }
13100
13172
  }
13173
+ else if (data.value_format_flags) {
13174
+ ctx.addIssue({
13175
+ code: zod.ZodIssueCode.custom,
13176
+ message: 'value_format is required for value_format_flags',
13177
+ });
13178
+ }
13101
13179
  }));
13102
13180
 
13103
13181
  /**
@@ -14700,7 +14778,7 @@ class RawFilterListConverter extends ConverterBase {
14700
14778
  return createConversionResult(rawFilterList, false);
14701
14779
  }
14702
14780
  // Otherwise, serialize the filter list and return the result
14703
- return createConversionResult(FilterListParser.generate(conversionResult.result), true);
14781
+ return createConversionResult(FilterListParser.generate(conversionResult.result, false, tolerant), true);
14704
14782
  }
14705
14783
  }
14706
14784
 
@@ -15648,7 +15726,7 @@ class RuleCategorizer {
15648
15726
  }
15649
15727
  }
15650
15728
 
15651
- const version = "2.1.3";
15729
+ const version = "2.2.0";
15652
15730
 
15653
15731
  /**
15654
15732
  * @file AGTree version
package/dist/agtree.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- * AGTree v2.1.3 (build date: Mon, 21 Oct 2024 08:22:25 GMT)
2
+ * AGTree v2.2.0 (build date: Wed, 27 Nov 2024 16:28:27 GMT)
3
3
  * (c) 2024 Adguard Software Ltd.
4
4
  * Released under the MIT license
5
5
  * https://github.com/AdguardTeam/tsurlfilter/tree/master/packages/agtree#readme
@@ -12,7 +12,6 @@ import { TokenType as TokenType$1, tokenizeExtended, getFormattedTokenName } fro
12
12
  import * as tldts from 'tldts';
13
13
  import { parse } from 'tldts';
14
14
  import isIp from 'is-ip';
15
- import XRegExp from 'xregexp';
16
15
  import cloneDeep from 'clone-deep';
17
16
  import { modifiersCompatibilityTableData, redirectsCompatibilityTableData, scriptletsCompatibilityTableData } from './compatibility-table-data.js';
18
17
  import zod from 'zod';
@@ -1893,6 +1892,9 @@ class AgentCommentRuleParser extends ParserBase {
1893
1892
  static serialize(node, buffer) {
1894
1893
  buffer.writeUint8(BinaryTypeMap.AgentRuleNode);
1895
1894
  const count = node.children.length;
1895
+ // If there are no children, we do not write any data related to them, to avoid using unnecessary storage,
1896
+ // but children is a required field, so during deserialization we should initialize it as an empty array,
1897
+ // if there are no children in the binary data.
1896
1898
  if (count) {
1897
1899
  buffer.writeUint8(AgentRuleSerializationMap.Children);
1898
1900
  // note: we store the count, because re-construction of the array is faster if we know the length
@@ -1947,6 +1949,11 @@ class AgentCommentRuleParser extends ParserBase {
1947
1949
  }
1948
1950
  prop = buffer.readUint8();
1949
1951
  }
1952
+ // Maybe children are not present in the binary data,
1953
+ // in this case, we should initialize it as an empty array.
1954
+ if (!node.children) {
1955
+ node.children = [];
1956
+ }
1950
1957
  }
1951
1958
  }
1952
1959
 
@@ -2842,6 +2849,9 @@ class HintCommentRuleParser extends ParserBase {
2842
2849
  buffer.writeUint8(SYNTAX_SERIALIZATION_MAP.get(AdblockSyntax.Adg) ?? 0);
2843
2850
  }
2844
2851
  const count = node.children.length;
2852
+ // If there are no children, we do not write any data related to them, to avoid using unnecessary storage,
2853
+ // but children is a required field, so during deserialization we should initialize it as an empty array,
2854
+ // if there are no children in the binary data.
2845
2855
  if (count) {
2846
2856
  buffer.writeUint8(HintRuleSerializationMap.Children);
2847
2857
  // note: we store the count, because re-construction of the array is faster if we know the length
@@ -2895,6 +2905,11 @@ class HintCommentRuleParser extends ParserBase {
2895
2905
  }
2896
2906
  prop = buffer.readUint8();
2897
2907
  }
2908
+ // Maybe children are not present in the binary data,
2909
+ // in this case, we should initialize it as an empty array.
2910
+ if (!node.children) {
2911
+ node.children = [];
2912
+ }
2898
2913
  }
2899
2914
  }
2900
2915
 
@@ -5328,6 +5343,9 @@ class ModifierListParser extends ParserBase {
5328
5343
  static serialize(node, buffer) {
5329
5344
  buffer.writeUint8(BinaryTypeMap.ModifierListNode);
5330
5345
  const count = node.children.length;
5346
+ // If there are no children, we do not write any data related to them, to avoid using unnecessary storage,
5347
+ // but children is a required field, so during deserialization we should initialize it as an empty array,
5348
+ // if there are no children in the binary data.
5331
5349
  if (count) {
5332
5350
  buffer.writeUint8(ModifierListNodeSerializationMap.Children);
5333
5351
  // note: we store the count, because re-construction of the array is faster if we know the length
@@ -5379,6 +5397,11 @@ class ModifierListParser extends ParserBase {
5379
5397
  }
5380
5398
  prop = buffer.readUint8();
5381
5399
  }
5400
+ // Maybe children are not present in the binary data,
5401
+ // in this case, we should initialize it as an empty array.
5402
+ if (!node.children) {
5403
+ node.children = [];
5404
+ }
5382
5405
  }
5383
5406
  }
5384
5407
 
@@ -8591,10 +8614,16 @@ class NetworkRuleParser extends ParserBase {
8591
8614
  const pattern = ValueParser.parse(raw.slice(patternStart, patternEnd), options, baseOffset + patternStart);
8592
8615
  // Parse modifiers (if any)
8593
8616
  let modifiers;
8617
+ // Get a last non-whitespace index
8618
+ const lastNonWsIndex = StringUtils.skipWSBack(raw);
8594
8619
  // Find start and end index of the modifiers
8595
8620
  const modifiersStart = separatorIndex + 1;
8596
- const modifiersEnd = StringUtils.skipWSBack(raw) + 1;
8621
+ const modifiersEnd = lastNonWsIndex + 1;
8597
8622
  if (separatorIndex !== -1) {
8623
+ // Check for empty modifiers
8624
+ if (separatorIndex === lastNonWsIndex) {
8625
+ throw new AdblockSyntaxError('Empty modifiers are not allowed', baseOffset + separatorIndex, baseOffset + raw.length);
8626
+ }
8598
8627
  modifiers = ModifierListParser.parse(raw.slice(modifiersStart, modifiersEnd), options, baseOffset + modifiersStart);
8599
8628
  }
8600
8629
  // Throw error if there is no pattern and no modifiers
@@ -8913,6 +8942,9 @@ class HostRuleParser extends ParserBase {
8913
8942
  buffer.writeUint32(node.end);
8914
8943
  }
8915
8944
  const count = node.children.length;
8945
+ // If there are no children, we do not write any data related to them, to avoid using unnecessary storage,
8946
+ // but children is a required field, so during deserialization we should initialize it as an empty array,
8947
+ // if there are no children in the binary data.
8916
8948
  if (count) {
8917
8949
  // note: we store the count, because re-construction of the array is faster if we know the length
8918
8950
  if (count > UINT16_MAX) {
@@ -8956,6 +8988,11 @@ class HostRuleParser extends ParserBase {
8956
8988
  }
8957
8989
  prop = buffer.readUint8();
8958
8990
  }
8991
+ // Maybe children are not present in the binary data,
8992
+ // in this case, we should initialize it as an empty array.
8993
+ if (!node.children) {
8994
+ node.children = [];
8995
+ }
8959
8996
  }
8960
8997
  /**
8961
8998
  * Serializes a host rule node to binary format.
@@ -9723,9 +9760,11 @@ class FilterListParser extends ParserBase {
9723
9760
  * @param ast AST to generate
9724
9761
  * @param preferRaw If `true`, then the parser will use `raws.text` property of each rule
9725
9762
  * if it is available. Default is `false`.
9763
+ * @param tolerant If `true`, errors during rule generation will be logged to the console and invalid rules
9764
+ * will be skipped. If `false`, an error will be thrown on the first invalid rule. Default is `true`.
9726
9765
  * @returns Serialized filter list
9727
9766
  */
9728
- static generate(ast, preferRaw = false) {
9767
+ static generate(ast, preferRaw = false, tolerant = true) {
9729
9768
  let result = EMPTY;
9730
9769
  for (let i = 0; i < ast.children.length; i += 1) {
9731
9770
  const rule = ast.children[i];
@@ -9733,7 +9772,18 @@ class FilterListParser extends ParserBase {
9733
9772
  result += rule.raws.text;
9734
9773
  }
9735
9774
  else {
9736
- result += RuleParser.generate(rule);
9775
+ try {
9776
+ result += RuleParser.generate(rule);
9777
+ }
9778
+ catch (error) {
9779
+ if (tolerant) {
9780
+ // eslint-disable-next-line no-console
9781
+ console.error(`Error when generating: ${error}`);
9782
+ }
9783
+ else {
9784
+ throw new Error(String(error));
9785
+ }
9786
+ }
9737
9787
  }
9738
9788
  switch (rule.raws?.nl) {
9739
9789
  case 'crlf':
@@ -10693,10 +10743,11 @@ const isCustomValueFormatValidator = (valueFormat) => {
10693
10743
  *
10694
10744
  * @param modifier Modifier AST node.
10695
10745
  * @param valueFormat Value format for the modifier.
10746
+ * @param valueFormatFlags Optional; RegExp flags for the value format.
10696
10747
  *
10697
10748
  * @returns Validation result.
10698
10749
  */
10699
- const validateValue = (modifier, valueFormat) => {
10750
+ const validateValue = (modifier, valueFormat, valueFormatFlags) => {
10700
10751
  if (isCustomValueFormatValidator(valueFormat)) {
10701
10752
  const validator = CUSTOM_VALUE_FORMAT_MAP[valueFormat];
10702
10753
  return validator(modifier);
@@ -10705,14 +10756,19 @@ const validateValue = (modifier, valueFormat) => {
10705
10756
  if (!modifier.value?.value) {
10706
10757
  return getValueRequiredValidationResult(modifierName);
10707
10758
  }
10708
- let xRegExp;
10759
+ let regExp;
10709
10760
  try {
10710
- xRegExp = XRegExp(valueFormat);
10761
+ if (isString(valueFormatFlags)) {
10762
+ regExp = new RegExp(valueFormat, valueFormatFlags);
10763
+ }
10764
+ else {
10765
+ regExp = new RegExp(valueFormat);
10766
+ }
10711
10767
  }
10712
10768
  catch (e) {
10713
10769
  throw new Error(`${SOURCE_DATA_ERROR_PREFIX.INVALID_VALUE_FORMAT_REGEXP}: '${modifierName}'`);
10714
10770
  }
10715
- const isValid = xRegExp.test(modifier.value?.value);
10771
+ const isValid = regExp.test(modifier.value?.value);
10716
10772
  if (!isValid) {
10717
10773
  return getInvalidValidationResult(`${VALIDATION_ERROR_PREFIX.VALUE_INVALID}: '${modifierName}'`);
10718
10774
  }
@@ -11296,7 +11352,7 @@ const validateForSpecificSyntax = (syntax, modifier, isException) => {
11296
11352
  if (!specificBlockerData.valueFormat) {
11297
11353
  throw new Error(`${SOURCE_DATA_ERROR_PREFIX.NO_VALUE_FORMAT_FOR_ASSIGNABLE}: '${modifierName}'`);
11298
11354
  }
11299
- return validateValue(modifier, specificBlockerData.valueFormat);
11355
+ return validateValue(modifier, specificBlockerData.valueFormat, specificBlockerData.valueFormatFlags);
11300
11356
  }
11301
11357
  if (modifier?.value) {
11302
11358
  // e.g. 'third-party=true'
@@ -12993,8 +13049,14 @@ function getErrorMessage(error) {
12993
13049
  * Known validators that don't need to be validated as regex.
12994
13050
  */
12995
13051
  const KNOWN_VALIDATORS = new Set([
13052
+ 'csp_value',
12996
13053
  'domain',
13054
+ 'permissions_value',
13055
+ 'pipe_separated_apps',
13056
+ 'pipe_separated_denyallow_domains',
12997
13057
  'pipe_separated_domains',
13058
+ 'pipe_separated_methods',
13059
+ 'pipe_separated_stealth_options',
12998
13060
  'regexp',
12999
13061
  'url',
13000
13062
  ]);
@@ -13045,6 +13107,10 @@ zodToCamelCase(baseCompatibilityDataSchema.extend({
13045
13107
  * Its value can be a regex pattern or a known validator name (e.g. `domain`, `pipe_separated_domains`, etc.).
13046
13108
  */
13047
13109
  value_format: nonEmptyStringSchema.nullable().default(null),
13110
+ /**
13111
+ * Describes the flags for the `value_format` regex pattern.
13112
+ */
13113
+ value_format_flags: nonEmptyStringSchema.nullable().default(null),
13048
13114
  }).superRefine((data, ctx) => {
13049
13115
  // TODO: find something better, for now we can't add refine logic to the base schema:
13050
13116
  // https://github.com/colinhacks/zod/issues/454#issuecomment-848370721
@@ -13065,11 +13131,17 @@ zodToCamelCase(baseCompatibilityDataSchema.extend({
13065
13131
  const valueFormat = data.value_format.trim();
13066
13132
  // if it is a known validator, we don't need to validate it further
13067
13133
  if (KNOWN_VALIDATORS.has(valueFormat)) {
13134
+ if (data.value_format_flags) {
13135
+ ctx.addIssue({
13136
+ code: zod.ZodIssueCode.custom,
13137
+ message: 'value_format_flags are not allowed for known validators',
13138
+ });
13139
+ }
13068
13140
  return;
13069
13141
  }
13070
13142
  // otherwise, we need to validate it as a regex
13071
13143
  try {
13072
- XRegExp(valueFormat);
13144
+ new RegExp(valueFormat, data.value_format_flags ?? EMPTY);
13073
13145
  }
13074
13146
  catch (error) {
13075
13147
  ctx.addIssue({
@@ -13078,6 +13150,12 @@ zodToCamelCase(baseCompatibilityDataSchema.extend({
13078
13150
  });
13079
13151
  }
13080
13152
  }
13153
+ else if (data.value_format_flags) {
13154
+ ctx.addIssue({
13155
+ code: zod.ZodIssueCode.custom,
13156
+ message: 'value_format is required for value_format_flags',
13157
+ });
13158
+ }
13081
13159
  }));
13082
13160
 
13083
13161
  /**
@@ -14680,7 +14758,7 @@ class RawFilterListConverter extends ConverterBase {
14680
14758
  return createConversionResult(rawFilterList, false);
14681
14759
  }
14682
14760
  // Otherwise, serialize the filter list and return the result
14683
- return createConversionResult(FilterListParser.generate(conversionResult.result), true);
14761
+ return createConversionResult(FilterListParser.generate(conversionResult.result, false, tolerant), true);
14684
14762
  }
14685
14763
  }
14686
14764
 
@@ -15628,7 +15706,7 @@ class RuleCategorizer {
15628
15706
  }
15629
15707
  }
15630
15708
 
15631
- const version = "2.1.3";
15709
+ const version = "2.2.0";
15632
15710
 
15633
15711
  /**
15634
15712
  * @file AGTree version