@adguard/agtree 2.2.0 → 2.3.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.2.0 (build date: Wed, 27 Nov 2024 16:28:27 GMT)
2
+ * AGTree v2.3.0 (build date: Thu, 19 Dec 2024 15:31:22 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
package/dist/agtree.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- * AGTree v2.2.0 (build date: Wed, 27 Nov 2024 16:28:27 GMT)
2
+ * AGTree v2.3.0 (build date: Thu, 19 Dec 2024 15:31:22 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
@@ -311,6 +311,8 @@ const COMMA_DOMAIN_LIST_SEPARATOR = ',';
311
311
  const PIPE_MODIFIER_SEPARATOR = '|';
312
312
  const CSS_MEDIA_MARKER = '@media';
313
313
  const CSS_NOT_PSEUDO = 'not';
314
+ const CSS_BLOCK_OPEN = '{';
315
+ const CSS_BLOCK_CLOSE = '}';
314
316
  const HINT_MARKER = '!+';
315
317
  const HINT_MARKER_LEN = HINT_MARKER.length;
316
318
  const NETWORK_RULE_EXCEPTION_MARKER = '@@';
@@ -6085,14 +6087,24 @@ class CssTokenStream {
6085
6087
  // - end: end index of the token
6086
6088
  // - props: additional properties of the token, if any (we don't use it here, this is why we use underscore)
6087
6089
  // - balance: balance level of the token
6088
- tokenizeBalanced(source, (type, start, end, _, balance) => {
6089
- this.tokens.push({
6090
- type,
6091
- start,
6092
- end,
6093
- balance,
6090
+ try {
6091
+ tokenizeBalanced(source, (type, start, end, _, balance) => {
6092
+ this.tokens.push({
6093
+ type,
6094
+ start,
6095
+ end,
6096
+ balance,
6097
+ });
6094
6098
  });
6095
- });
6099
+ }
6100
+ catch (error) {
6101
+ // If the error is an AdblockSyntaxError, adjust the error positions to the base offset
6102
+ if (error instanceof AdblockSyntaxError) {
6103
+ error.start += baseOffset;
6104
+ error.end += baseOffset;
6105
+ throw error;
6106
+ }
6107
+ }
6096
6108
  this.index = 0;
6097
6109
  this.baseOffset = baseOffset;
6098
6110
  }
@@ -7652,6 +7664,40 @@ class AdgScriptletInjectionBodyParser extends ParserBase {
7652
7664
  }
7653
7665
  }
7654
7666
 
7667
+ /**
7668
+ * Represents an error that occurs when an operation is aborted.
7669
+ */
7670
+ class AbortError extends Error {
7671
+ constructor() {
7672
+ super('Aborted');
7673
+ }
7674
+ }
7675
+ // TODO: AG-38480 add a stop function to the tokenizers callback and move `hasToken` to CSS Tokenizer as well
7676
+ /**
7677
+ * Checks if the given raw string contains any of the specified tokens.
7678
+ * This function uses error throwing inside the abort tokenization process.
7679
+ *
7680
+ * @param raw - The raw string to be tokenized and checked.
7681
+ * @param tokens - A set of token types to check for in the raw string.
7682
+ * @returns `true` if any of the specified tokens are found in the raw string, otherwise `false`.
7683
+ */
7684
+ const hasToken = (raw, tokens) => {
7685
+ try {
7686
+ cssTokenizer.tokenizeExtended(raw, (type) => {
7687
+ if (tokens.has(type)) {
7688
+ throw new AbortError();
7689
+ }
7690
+ });
7691
+ }
7692
+ catch (e) {
7693
+ if (e instanceof AbortError) {
7694
+ return true;
7695
+ }
7696
+ throw e;
7697
+ }
7698
+ return false;
7699
+ };
7700
+
7655
7701
  /* eslint-disable no-param-reassign */
7656
7702
  /**
7657
7703
  * Value map for binary serialization. This helps to reduce the size of the serialized data,
@@ -8024,6 +8070,33 @@ class CosmeticRuleParser extends ParserBase {
8024
8070
  body: AdgCssInjectionParser.parse(rawBody, options, baseOffset + bodyStart),
8025
8071
  };
8026
8072
  };
8073
+ /**
8074
+ * Parses Adb CSS injection rules
8075
+ * eg: example.com##.foo { display: none; }
8076
+ *
8077
+ * @returns parsed rule
8078
+ */
8079
+ const parseAbpCssInjection = () => {
8080
+ if (!options.parseAbpSpecificRules) {
8081
+ return null;
8082
+ }
8083
+ // check if the rule contains both CSS block open and close characters
8084
+ // if none of them is present we can stop parsing
8085
+ if (rawBody.indexOf(CSS_BLOCK_OPEN) === -1 && rawBody.indexOf(CSS_BLOCK_CLOSE) === -1) {
8086
+ return null;
8087
+ }
8088
+ if (!hasToken(rawBody, new Set([cssTokenizer.TokenType.OpenCurlyBracket, cssTokenizer.TokenType.CloseCurlyBracket]))) {
8089
+ return null;
8090
+ }
8091
+ // try to parse the raw body as an AdGuard CSS injection rule
8092
+ const body = AdgCssInjectionParser.parse(rawBody, options, baseOffset + bodyStart);
8093
+ // if the parsed rule type is a 'CssInjectionRuleBody', return the parsed rule
8094
+ return {
8095
+ syntax: exports.AdblockSyntax.Abp,
8096
+ type: exports.CosmeticRuleType.CssInjectionRule,
8097
+ body,
8098
+ };
8099
+ };
8027
8100
  const parseAbpSnippetInjection = () => {
8028
8101
  if (!options.parseAbpSpecificRules) {
8029
8102
  throw new AdblockSyntaxError(sprintfJs.sprintf(ERROR_MESSAGES$3.SYNTAX_DISABLED, exports.AdblockSyntax.Abp), baseOffset + bodyStart, baseOffset + bodyEnd);
@@ -8135,10 +8208,22 @@ class CosmeticRuleParser extends ParserBase {
8135
8208
  // the next function is called, and so on.
8136
8209
  // If all functions return null, an error should be thrown.
8137
8210
  const separatorMap = {
8138
- '##': [parseUboHtmlFiltering, parseUboScriptletInjection, parseUboCssInjection, parseElementHiding],
8139
- '#@#': [parseUboHtmlFiltering, parseUboScriptletInjection, parseUboCssInjection, parseElementHiding],
8140
- '#?#': [parseUboCssInjection, parseElementHiding],
8141
- '#@?#': [parseUboCssInjection, parseElementHiding],
8211
+ '##': [
8212
+ parseUboHtmlFiltering,
8213
+ parseUboScriptletInjection,
8214
+ parseUboCssInjection,
8215
+ parseAbpCssInjection,
8216
+ parseElementHiding,
8217
+ ],
8218
+ '#@#': [
8219
+ parseUboHtmlFiltering,
8220
+ parseUboScriptletInjection,
8221
+ parseUboCssInjection,
8222
+ parseAbpCssInjection,
8223
+ parseElementHiding,
8224
+ ],
8225
+ '#?#': [parseUboCssInjection, parseAbpCssInjection, parseElementHiding],
8226
+ '#@?#': [parseUboCssInjection, parseAbpCssInjection, parseElementHiding],
8142
8227
  '#$#': [parseAdgCssInjection, parseAbpSnippetInjection],
8143
8228
  '#@$#': [parseAdgCssInjection, parseAbpSnippetInjection],
8144
8229
  '#$?#': [parseAdgCssInjection],
@@ -8207,7 +8292,7 @@ class CosmeticRuleParser extends ParserBase {
8207
8292
  result = node.body.selectorList.value;
8208
8293
  break;
8209
8294
  case exports.CosmeticRuleType.CssInjectionRule:
8210
- if (node.syntax === exports.AdblockSyntax.Adg) {
8295
+ if (node.syntax === exports.AdblockSyntax.Adg || node.syntax === exports.AdblockSyntax.Abp) {
8211
8296
  result = AdgCssInjectionParser.generate(node.body);
8212
8297
  }
8213
8298
  else if (node.syntax === exports.AdblockSyntax.Ubo) {
@@ -15726,7 +15811,7 @@ class RuleCategorizer {
15726
15811
  }
15727
15812
  }
15728
15813
 
15729
- const version = "2.2.0";
15814
+ const version = "2.3.0";
15730
15815
 
15731
15816
  /**
15732
15817
  * @file AGTree version
package/dist/agtree.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- * AGTree v2.2.0 (build date: Wed, 27 Nov 2024 16:28:27 GMT)
2
+ * AGTree v2.3.0 (build date: Thu, 19 Dec 2024 15:31:22 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
@@ -291,6 +291,8 @@ const COMMA_DOMAIN_LIST_SEPARATOR = ',';
291
291
  const PIPE_MODIFIER_SEPARATOR = '|';
292
292
  const CSS_MEDIA_MARKER = '@media';
293
293
  const CSS_NOT_PSEUDO = 'not';
294
+ const CSS_BLOCK_OPEN = '{';
295
+ const CSS_BLOCK_CLOSE = '}';
294
296
  const HINT_MARKER = '!+';
295
297
  const HINT_MARKER_LEN = HINT_MARKER.length;
296
298
  const NETWORK_RULE_EXCEPTION_MARKER = '@@';
@@ -6065,14 +6067,24 @@ class CssTokenStream {
6065
6067
  // - end: end index of the token
6066
6068
  // - props: additional properties of the token, if any (we don't use it here, this is why we use underscore)
6067
6069
  // - balance: balance level of the token
6068
- tokenizeBalanced(source, (type, start, end, _, balance) => {
6069
- this.tokens.push({
6070
- type,
6071
- start,
6072
- end,
6073
- balance,
6070
+ try {
6071
+ tokenizeBalanced(source, (type, start, end, _, balance) => {
6072
+ this.tokens.push({
6073
+ type,
6074
+ start,
6075
+ end,
6076
+ balance,
6077
+ });
6074
6078
  });
6075
- });
6079
+ }
6080
+ catch (error) {
6081
+ // If the error is an AdblockSyntaxError, adjust the error positions to the base offset
6082
+ if (error instanceof AdblockSyntaxError) {
6083
+ error.start += baseOffset;
6084
+ error.end += baseOffset;
6085
+ throw error;
6086
+ }
6087
+ }
6076
6088
  this.index = 0;
6077
6089
  this.baseOffset = baseOffset;
6078
6090
  }
@@ -7632,6 +7644,40 @@ class AdgScriptletInjectionBodyParser extends ParserBase {
7632
7644
  }
7633
7645
  }
7634
7646
 
7647
+ /**
7648
+ * Represents an error that occurs when an operation is aborted.
7649
+ */
7650
+ class AbortError extends Error {
7651
+ constructor() {
7652
+ super('Aborted');
7653
+ }
7654
+ }
7655
+ // TODO: AG-38480 add a stop function to the tokenizers callback and move `hasToken` to CSS Tokenizer as well
7656
+ /**
7657
+ * Checks if the given raw string contains any of the specified tokens.
7658
+ * This function uses error throwing inside the abort tokenization process.
7659
+ *
7660
+ * @param raw - The raw string to be tokenized and checked.
7661
+ * @param tokens - A set of token types to check for in the raw string.
7662
+ * @returns `true` if any of the specified tokens are found in the raw string, otherwise `false`.
7663
+ */
7664
+ const hasToken = (raw, tokens) => {
7665
+ try {
7666
+ tokenizeExtended(raw, (type) => {
7667
+ if (tokens.has(type)) {
7668
+ throw new AbortError();
7669
+ }
7670
+ });
7671
+ }
7672
+ catch (e) {
7673
+ if (e instanceof AbortError) {
7674
+ return true;
7675
+ }
7676
+ throw e;
7677
+ }
7678
+ return false;
7679
+ };
7680
+
7635
7681
  /* eslint-disable no-param-reassign */
7636
7682
  /**
7637
7683
  * Value map for binary serialization. This helps to reduce the size of the serialized data,
@@ -8004,6 +8050,33 @@ class CosmeticRuleParser extends ParserBase {
8004
8050
  body: AdgCssInjectionParser.parse(rawBody, options, baseOffset + bodyStart),
8005
8051
  };
8006
8052
  };
8053
+ /**
8054
+ * Parses Adb CSS injection rules
8055
+ * eg: example.com##.foo { display: none; }
8056
+ *
8057
+ * @returns parsed rule
8058
+ */
8059
+ const parseAbpCssInjection = () => {
8060
+ if (!options.parseAbpSpecificRules) {
8061
+ return null;
8062
+ }
8063
+ // check if the rule contains both CSS block open and close characters
8064
+ // if none of them is present we can stop parsing
8065
+ if (rawBody.indexOf(CSS_BLOCK_OPEN) === -1 && rawBody.indexOf(CSS_BLOCK_CLOSE) === -1) {
8066
+ return null;
8067
+ }
8068
+ if (!hasToken(rawBody, new Set([TokenType$1.OpenCurlyBracket, TokenType$1.CloseCurlyBracket]))) {
8069
+ return null;
8070
+ }
8071
+ // try to parse the raw body as an AdGuard CSS injection rule
8072
+ const body = AdgCssInjectionParser.parse(rawBody, options, baseOffset + bodyStart);
8073
+ // if the parsed rule type is a 'CssInjectionRuleBody', return the parsed rule
8074
+ return {
8075
+ syntax: AdblockSyntax.Abp,
8076
+ type: CosmeticRuleType.CssInjectionRule,
8077
+ body,
8078
+ };
8079
+ };
8007
8080
  const parseAbpSnippetInjection = () => {
8008
8081
  if (!options.parseAbpSpecificRules) {
8009
8082
  throw new AdblockSyntaxError(sprintf(ERROR_MESSAGES$3.SYNTAX_DISABLED, AdblockSyntax.Abp), baseOffset + bodyStart, baseOffset + bodyEnd);
@@ -8115,10 +8188,22 @@ class CosmeticRuleParser extends ParserBase {
8115
8188
  // the next function is called, and so on.
8116
8189
  // If all functions return null, an error should be thrown.
8117
8190
  const separatorMap = {
8118
- '##': [parseUboHtmlFiltering, parseUboScriptletInjection, parseUboCssInjection, parseElementHiding],
8119
- '#@#': [parseUboHtmlFiltering, parseUboScriptletInjection, parseUboCssInjection, parseElementHiding],
8120
- '#?#': [parseUboCssInjection, parseElementHiding],
8121
- '#@?#': [parseUboCssInjection, parseElementHiding],
8191
+ '##': [
8192
+ parseUboHtmlFiltering,
8193
+ parseUboScriptletInjection,
8194
+ parseUboCssInjection,
8195
+ parseAbpCssInjection,
8196
+ parseElementHiding,
8197
+ ],
8198
+ '#@#': [
8199
+ parseUboHtmlFiltering,
8200
+ parseUboScriptletInjection,
8201
+ parseUboCssInjection,
8202
+ parseAbpCssInjection,
8203
+ parseElementHiding,
8204
+ ],
8205
+ '#?#': [parseUboCssInjection, parseAbpCssInjection, parseElementHiding],
8206
+ '#@?#': [parseUboCssInjection, parseAbpCssInjection, parseElementHiding],
8122
8207
  '#$#': [parseAdgCssInjection, parseAbpSnippetInjection],
8123
8208
  '#@$#': [parseAdgCssInjection, parseAbpSnippetInjection],
8124
8209
  '#$?#': [parseAdgCssInjection],
@@ -8187,7 +8272,7 @@ class CosmeticRuleParser extends ParserBase {
8187
8272
  result = node.body.selectorList.value;
8188
8273
  break;
8189
8274
  case CosmeticRuleType.CssInjectionRule:
8190
- if (node.syntax === AdblockSyntax.Adg) {
8275
+ if (node.syntax === AdblockSyntax.Adg || node.syntax === AdblockSyntax.Abp) {
8191
8276
  result = AdgCssInjectionParser.generate(node.body);
8192
8277
  }
8193
8278
  else if (node.syntax === AdblockSyntax.Ubo) {
@@ -15706,7 +15791,7 @@ class RuleCategorizer {
15706
15791
  }
15707
15792
  }
15708
15793
 
15709
- const version = "2.2.0";
15794
+ const version = "2.3.0";
15710
15795
 
15711
15796
  /**
15712
15797
  * @file AGTree version
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adguard/agtree",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Tool set for working with adblock filter lists",
5
5
  "keywords": [
6
6
  "adblock",