@adguard/agtree 4.0.1 → 4.0.3

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 (284) hide show
  1. package/README.md +4 -3
  2. package/dist/ast-utils/clone.js +12 -8
  3. package/dist/ast-utils/modifiers.js +13 -11
  4. package/dist/ast-utils/network-rules.js +10 -9
  5. package/dist/ast-utils/scriptlets.js +20 -18
  6. package/dist/common/abp-snippet-injection-body-common.js +1 -1
  7. package/dist/common/agent-common.js +1 -1
  8. package/dist/common/ubo-html-filtering-body-common.js +1 -1
  9. package/dist/common/ubo-selector-common.js +1 -1
  10. package/dist/compatibility-tables/base.js +7 -6
  11. package/dist/compatibility-tables/compatibility-table-data.js +1 -1
  12. package/dist/compatibility-tables/modifiers.js +4 -3
  13. package/dist/compatibility-tables/platforms.js +1 -1
  14. package/dist/compatibility-tables/redirects.js +4 -4
  15. package/dist/compatibility-tables/schemas/base.js +2 -2
  16. package/dist/compatibility-tables/schemas/modifier.js +4 -4
  17. package/dist/compatibility-tables/schemas/platform.js +3 -2
  18. package/dist/compatibility-tables/schemas/redirect.js +1 -1
  19. package/dist/compatibility-tables/schemas/resource-type.js +1 -1
  20. package/dist/compatibility-tables/schemas/scriptlet.js +1 -1
  21. package/dist/compatibility-tables/scriptlets.js +2 -2
  22. package/dist/compatibility-tables/utils/platform-helpers.js +6 -4
  23. package/dist/compatibility-tables/utils/resource-type-helpers.js +1 -1
  24. package/dist/compatibility-tables/utils/zod-camelcase.js +3 -3
  25. package/dist/converter/base-interfaces/base-converter.js +22 -16
  26. package/dist/converter/base-interfaces/conversion-result.js +15 -11
  27. package/dist/converter/base-interfaces/rule-converter-base.js +19 -13
  28. package/dist/converter/comment/index.js +11 -9
  29. package/dist/converter/cosmetic/css.js +12 -10
  30. package/dist/converter/cosmetic/element-hiding.js +12 -10
  31. package/dist/converter/cosmetic/header-removal.js +16 -13
  32. package/dist/converter/cosmetic/html.js +107 -20
  33. package/dist/converter/cosmetic/index.js +28 -24
  34. package/dist/converter/cosmetic/rule-modifiers/adg.js +15 -12
  35. package/dist/converter/cosmetic/rule-modifiers/ubo.js +22 -19
  36. package/dist/converter/cosmetic/scriptlet.js +26 -22
  37. package/dist/converter/css/index.js +13 -11
  38. package/dist/converter/data/css.js +8 -8
  39. package/dist/converter/filter-list.js +12 -10
  40. package/dist/converter/index.js +1 -1
  41. package/dist/converter/misc/network-rule-modifier.js +20 -16
  42. package/dist/converter/network/index.js +16 -12
  43. package/dist/converter/raw-filter-list.js +12 -10
  44. package/dist/converter/raw-rule.js +14 -12
  45. package/dist/converter/rule.js +17 -13
  46. package/dist/errors/adblock-syntax-error.js +1 -1
  47. package/dist/errors/not-implemented-error.js +2 -2
  48. package/dist/errors/rule-conversion-error.js +2 -2
  49. package/dist/generator/base-generator.js +1 -1
  50. package/dist/generator/comment/agent-comment-generator.js +4 -3
  51. package/dist/generator/comment/agent-generator.js +5 -4
  52. package/dist/generator/comment/comment-rule-generator.js +6 -5
  53. package/dist/generator/comment/config-comment-generator.js +5 -4
  54. package/dist/generator/comment/hint-comment-generator.js +5 -4
  55. package/dist/generator/comment/hint-generator.js +4 -3
  56. package/dist/generator/comment/metadata-comment-generator.js +3 -2
  57. package/dist/generator/comment/pre-processor-comment-generator.js +6 -5
  58. package/dist/generator/comment/simple-comment-generator.js +3 -2
  59. package/dist/generator/cosmetic/cosmetic-rule-body-generator.js +13 -11
  60. package/dist/generator/cosmetic/cosmetic-rule-generator.js +5 -4
  61. package/dist/generator/cosmetic/cosmetic-rule-pattern-generator.js +7 -5
  62. package/dist/generator/cosmetic/html-filtering-body/adg-html-filtering-body-generator.js +3 -3
  63. package/dist/generator/cosmetic/html-filtering-body/html-filtering-body-generator.js +1 -1
  64. package/dist/generator/cosmetic/html-filtering-body/ubo-html-filtering-body-generator.js +2 -2
  65. package/dist/generator/cosmetic/scriptlet-body/abp-snippet-injection-body-generator.js +7 -5
  66. package/dist/generator/cosmetic/scriptlet-body/adg-scriptlet-injection-body-generator.js +7 -5
  67. package/dist/generator/cosmetic/scriptlet-body/ubo-scriptlet-injection-body-generator.js +8 -6
  68. package/dist/generator/cosmetic/selector/attribute-selector-generator.js +2 -2
  69. package/dist/generator/cosmetic/selector/class-selector-generator.js +1 -1
  70. package/dist/generator/cosmetic/selector/complex-selector-generator.js +4 -4
  71. package/dist/generator/cosmetic/selector/id-selector-generator.js +1 -1
  72. package/dist/generator/cosmetic/selector/pseudo-class-selector-generator.js +1 -1
  73. package/dist/generator/cosmetic/selector/selector-combinator-generator.js +1 -1
  74. package/dist/generator/cosmetic/selector/selector-list-generator.js +1 -1
  75. package/dist/generator/cosmetic/selector/type-selector-generator.js +1 -1
  76. package/dist/generator/css/adg-css-injection-generator.js +5 -1
  77. package/dist/generator/filterlist-generator.js +5 -4
  78. package/dist/generator/index.js +1 -1
  79. package/dist/generator/misc/domain-list-generator.js +1 -1
  80. package/dist/generator/misc/list-items-generator.js +5 -3
  81. package/dist/generator/misc/logical-expression-generator.js +5 -4
  82. package/dist/generator/misc/modifier-generator.js +4 -3
  83. package/dist/generator/misc/modifier-list-generator.js +5 -4
  84. package/dist/generator/misc/parameter-list-generator.js +6 -5
  85. package/dist/generator/misc/value-generator.js +2 -1
  86. package/dist/generator/network/host-rule-generator.js +2 -1
  87. package/dist/generator/network/network-rule-generator.js +2 -1
  88. package/dist/generator/rule-generator.js +6 -4
  89. package/dist/index.js +1 -2
  90. package/dist/nodes/index.js +1 -1
  91. package/dist/package.json.js +2 -2
  92. package/dist/parser/base-parser.js +1 -1
  93. package/dist/parser/comment/agent-comment-parser.js +11 -9
  94. package/dist/parser/comment/agent-parser.js +12 -9
  95. package/dist/parser/comment/comment-parser.js +8 -7
  96. package/dist/parser/comment/config-comment-parser.js +9 -6
  97. package/dist/parser/comment/hint-comment-parser.js +17 -12
  98. package/dist/parser/comment/hint-parser.js +10 -7
  99. package/dist/parser/comment/metadata-comment-parser.js +9 -7
  100. package/dist/parser/comment/preprocessor-parser.js +14 -11
  101. package/dist/parser/comment/simple-comment-parser.js +5 -2
  102. package/dist/parser/cosmetic/cosmetic-rule-parser.js +29 -25
  103. package/dist/parser/cosmetic/html-filtering-body/adg-html-filtering-body-parser.js +3 -3
  104. package/dist/parser/cosmetic/html-filtering-body/html-filtering-body-parser.js +4 -4
  105. package/dist/parser/cosmetic/html-filtering-body/ubo-html-filtering-body-parser.js +7 -7
  106. package/dist/parser/cosmetic/scriptlet-body/abp-snippet-injection-body-parser.js +12 -9
  107. package/dist/parser/cosmetic/scriptlet-body/adg-scriptlet-injection-body-parser.js +12 -9
  108. package/dist/parser/cosmetic/scriptlet-body/ubo-scriptlet-injection-body-parser.js +11 -8
  109. package/dist/parser/cosmetic/selector/handlers/attribute-selector-handler.js +1 -1
  110. package/dist/parser/cosmetic/selector/handlers/class-selector-handler.js +1 -1
  111. package/dist/parser/cosmetic/selector/handlers/complex-selector-handler.js +1 -1
  112. package/dist/parser/cosmetic/selector/handlers/compound-selector-handler.js +2 -2
  113. package/dist/parser/cosmetic/selector/handlers/id-selector-handler.js +1 -1
  114. package/dist/parser/cosmetic/selector/handlers/pseudo-class-selector-handler.js +5 -3
  115. package/dist/parser/cosmetic/selector/handlers/type-selector-handler.js +1 -1
  116. package/dist/parser/cosmetic/selector/selector-list-parser.js +7 -7
  117. package/dist/parser/css/adg-css-injection-parser.js +4 -3
  118. package/dist/parser/css/balancing.js +22 -18
  119. package/dist/parser/css/constants.js +1 -1
  120. package/dist/parser/css/css-token-stream.js +15 -4
  121. package/dist/parser/css/ubo-selector-parser.js +8 -4
  122. package/dist/parser/filterlist-parser.js +8 -5
  123. package/dist/parser/index.js +1 -1
  124. package/dist/parser/misc/app-list-parser.js +4 -3
  125. package/dist/parser/misc/domain-list-parser.js +8 -6
  126. package/dist/parser/misc/list-items-parser.js +8 -6
  127. package/dist/parser/misc/logical-expression-parser.js +25 -18
  128. package/dist/parser/misc/method-list-parser.js +4 -3
  129. package/dist/parser/misc/modifier-list.js +3 -3
  130. package/dist/parser/misc/modifier-parser.js +5 -4
  131. package/dist/parser/misc/parameter-list-parser.js +6 -5
  132. package/dist/parser/misc/stealth-option-list-parser.js +4 -3
  133. package/dist/parser/misc/ubo-parameter-list-parser.js +10 -9
  134. package/dist/parser/misc/value-parser.js +2 -2
  135. package/dist/parser/network/host-rule-parser.js +15 -7
  136. package/dist/parser/network/network-rule-parser.js +11 -9
  137. package/dist/parser/options.js +1 -1
  138. package/dist/parser/rule-parser.js +11 -7
  139. package/dist/types/ast-utils/clone.d.ts +12 -8
  140. package/dist/types/ast-utils/filter-list.d.ts +5 -4
  141. package/dist/types/ast-utils/modifiers.d.ts +11 -9
  142. package/dist/types/ast-utils/network-rules.d.ts +8 -7
  143. package/dist/types/ast-utils/scriptlets.d.ts +19 -17
  144. package/dist/types/compatibility-tables/base.d.ts +6 -5
  145. package/dist/types/compatibility-tables/redirects.d.ts +1 -1
  146. package/dist/types/compatibility-tables/schemas/platform.d.ts +1 -0
  147. package/dist/types/compatibility-tables/utils/platform-helpers.d.ts +5 -3
  148. package/dist/types/compatibility-tables/utils/zod-camelcase.d.ts +3 -3
  149. package/dist/types/converter/base-interfaces/base-converter.d.ts +21 -15
  150. package/dist/types/converter/base-interfaces/conversion-result.d.ts +20 -16
  151. package/dist/types/converter/base-interfaces/rule-converter-base.d.ts +19 -13
  152. package/dist/types/converter/comment/index.d.ts +9 -7
  153. package/dist/types/converter/cosmetic/css.d.ts +9 -7
  154. package/dist/types/converter/cosmetic/element-hiding.d.ts +9 -7
  155. package/dist/types/converter/cosmetic/header-removal.d.ts +10 -7
  156. package/dist/types/converter/cosmetic/html.d.ts +29 -9
  157. package/dist/types/converter/cosmetic/index.d.ts +14 -10
  158. package/dist/types/converter/cosmetic/rule-modifiers/adg.d.ts +9 -6
  159. package/dist/types/converter/cosmetic/rule-modifiers/ubo.d.ts +9 -6
  160. package/dist/types/converter/cosmetic/scriptlet.d.ts +14 -10
  161. package/dist/types/converter/css/index.d.ts +9 -7
  162. package/dist/types/converter/data/css.d.ts +1 -1
  163. package/dist/types/converter/filter-list.d.ts +10 -8
  164. package/dist/types/converter/index.d.ts +1 -1
  165. package/dist/types/converter/misc/network-rule-modifier.d.ts +13 -9
  166. package/dist/types/converter/network/index.d.ts +15 -11
  167. package/dist/types/converter/raw-filter-list.d.ts +8 -6
  168. package/dist/types/converter/raw-rule.d.ts +8 -6
  169. package/dist/types/converter/rule.d.ts +14 -10
  170. package/dist/types/errors/not-implemented-error.d.ts +1 -1
  171. package/dist/types/errors/rule-conversion-error.d.ts +1 -1
  172. package/dist/types/generator/comment/agent-comment-generator.d.ts +3 -2
  173. package/dist/types/generator/comment/agent-generator.d.ts +4 -3
  174. package/dist/types/generator/comment/comment-rule-generator.d.ts +3 -2
  175. package/dist/types/generator/comment/config-comment-generator.d.ts +4 -3
  176. package/dist/types/generator/comment/hint-comment-generator.d.ts +4 -3
  177. package/dist/types/generator/comment/hint-generator.d.ts +3 -2
  178. package/dist/types/generator/comment/metadata-comment-generator.d.ts +1 -0
  179. package/dist/types/generator/comment/pre-processor-comment-generator.d.ts +3 -2
  180. package/dist/types/generator/comment/simple-comment-generator.d.ts +2 -1
  181. package/dist/types/generator/cosmetic/cosmetic-rule-body-generator.d.ts +7 -5
  182. package/dist/types/generator/cosmetic/cosmetic-rule-generator.d.ts +3 -2
  183. package/dist/types/generator/cosmetic/cosmetic-rule-pattern-generator.d.ts +4 -2
  184. package/dist/types/generator/cosmetic/html-filtering-body/adg-html-filtering-body-generator.d.ts +1 -1
  185. package/dist/types/generator/cosmetic/html-filtering-body/html-filtering-body-generator.d.ts +1 -1
  186. package/dist/types/generator/cosmetic/html-filtering-body/ubo-html-filtering-body-generator.d.ts +2 -2
  187. package/dist/types/generator/cosmetic/scriptlet-body/abp-snippet-injection-body-generator.d.ts +5 -3
  188. package/dist/types/generator/cosmetic/scriptlet-body/adg-scriptlet-injection-body-generator.d.ts +5 -3
  189. package/dist/types/generator/cosmetic/scriptlet-body/ubo-scriptlet-injection-body-generator.d.ts +7 -5
  190. package/dist/types/generator/css/adg-css-injection-generator.d.ts +4 -0
  191. package/dist/types/generator/css/ubo-selector-generator.d.ts +4 -3
  192. package/dist/types/generator/filterlist-generator.d.ts +3 -2
  193. package/dist/types/generator/misc/list-items-generator.d.ts +4 -2
  194. package/dist/types/generator/misc/logical-expression-generator.d.ts +4 -3
  195. package/dist/types/generator/misc/modifier-generator.d.ts +3 -2
  196. package/dist/types/generator/misc/modifier-list-generator.d.ts +4 -3
  197. package/dist/types/generator/misc/parameter-list-generator.d.ts +5 -4
  198. package/dist/types/generator/misc/value-generator.d.ts +1 -0
  199. package/dist/types/generator/network/host-rule-generator.d.ts +1 -0
  200. package/dist/types/generator/network/network-rule-generator.d.ts +1 -0
  201. package/dist/types/generator/rule-generator.d.ts +5 -3
  202. package/dist/types/index.d.ts +1 -2
  203. package/dist/types/nodes/index.d.ts +55 -54
  204. package/dist/types/parser/comment/agent-comment-parser.d.ts +5 -3
  205. package/dist/types/parser/comment/agent-parser.d.ts +7 -4
  206. package/dist/types/parser/comment/comment-parser.d.ts +5 -3
  207. package/dist/types/parser/comment/config-comment-parser.d.ts +5 -2
  208. package/dist/types/parser/comment/hint-comment-parser.d.ts +11 -6
  209. package/dist/types/parser/comment/hint-parser.d.ts +6 -3
  210. package/dist/types/parser/comment/metadata-comment-parser.d.ts +5 -3
  211. package/dist/types/parser/comment/preprocessor-parser.d.ts +9 -6
  212. package/dist/types/parser/comment/simple-comment-parser.d.ts +3 -0
  213. package/dist/types/parser/cosmetic/cosmetic-rule-parser.d.ts +9 -6
  214. package/dist/types/parser/cosmetic/html-filtering-body/adg-html-filtering-body-parser.d.ts +3 -3
  215. package/dist/types/parser/cosmetic/html-filtering-body/html-filtering-body-parser.d.ts +4 -4
  216. package/dist/types/parser/cosmetic/html-filtering-body/ubo-html-filtering-body-parser.d.ts +4 -4
  217. package/dist/types/parser/cosmetic/scriptlet-body/abp-snippet-injection-body-parser.d.ts +8 -5
  218. package/dist/types/parser/cosmetic/scriptlet-body/adg-scriptlet-injection-body-parser.d.ts +9 -6
  219. package/dist/types/parser/cosmetic/scriptlet-body/ubo-scriptlet-injection-body-parser.d.ts +8 -5
  220. package/dist/types/parser/cosmetic/selector/context.d.ts +2 -2
  221. package/dist/types/parser/cosmetic/selector/selector-list-parser.d.ts +2 -2
  222. package/dist/types/parser/css/adg-css-injection-parser.d.ts +1 -0
  223. package/dist/types/parser/css/balancing.d.ts +17 -12
  224. package/dist/types/parser/css/css-token-stream.d.ts +11 -0
  225. package/dist/types/parser/css/ubo-selector-parser.d.ts +3 -0
  226. package/dist/types/parser/filterlist-parser.d.ts +5 -2
  227. package/dist/types/parser/misc/app-list-parser.d.ts +1 -0
  228. package/dist/types/parser/misc/domain-list-parser.d.ts +5 -3
  229. package/dist/types/parser/misc/list-items-parser.d.ts +5 -3
  230. package/dist/types/parser/misc/logical-expression-parser.d.ts +9 -5
  231. package/dist/types/parser/misc/method-list-parser.d.ts +1 -0
  232. package/dist/types/parser/misc/modifier-list.d.ts +2 -1
  233. package/dist/types/parser/misc/modifier-parser.d.ts +2 -1
  234. package/dist/types/parser/misc/parameter-list-parser.d.ts +3 -2
  235. package/dist/types/parser/misc/stealth-option-list-parser.d.ts +1 -0
  236. package/dist/types/parser/misc/ubo-parameter-list-parser.d.ts +2 -1
  237. package/dist/types/parser/misc/value-parser.d.ts +1 -1
  238. package/dist/types/parser/network/host-rule-parser.d.ts +10 -2
  239. package/dist/types/parser/network/network-rule-parser.d.ts +5 -3
  240. package/dist/types/parser/options.d.ts +1 -1
  241. package/dist/types/parser/rule-parser.d.ts +6 -2
  242. package/dist/types/tokenizer/tokenizer.d.ts +2 -2
  243. package/dist/types/utils/adblockers.d.ts +9 -6
  244. package/dist/types/utils/clone.d.ts +4 -3
  245. package/dist/types/utils/constants.d.ts +1 -1
  246. package/dist/types/utils/cosmetic-rule-separator.d.ts +13 -10
  247. package/dist/types/utils/deep-freeze.d.ts +4 -4
  248. package/dist/types/utils/domain.d.ts +3 -2
  249. package/dist/types/utils/logical-expression.d.ts +9 -5
  250. package/dist/types/utils/multi-value-map.d.ts +3 -3
  251. package/dist/types/utils/position-provider.d.ts +3 -2
  252. package/dist/types/utils/quotes.d.ts +48 -42
  253. package/dist/types/utils/regexp.d.ts +24 -17
  254. package/dist/types/utils/string.d.ts +135 -103
  255. package/dist/types/utils/type-guards.d.ts +1 -0
  256. package/dist/types/validator/helpers.d.ts +1 -1
  257. package/dist/types/validator/index.d.ts +3 -3
  258. package/dist/types/version.d.ts +1 -1
  259. package/dist/utils/adblockers.js +10 -7
  260. package/dist/utils/bit-count.js +1 -1
  261. package/dist/utils/categorizer.js +2 -2
  262. package/dist/utils/clone.js +5 -4
  263. package/dist/utils/constants.js +2 -2
  264. package/dist/utils/cosmetic-rule-separator.js +15 -11
  265. package/dist/utils/deep-freeze.js +5 -5
  266. package/dist/utils/domain.js +4 -3
  267. package/dist/utils/error.js +3 -1
  268. package/dist/utils/index.js +1 -1
  269. package/dist/utils/logical-expression.js +10 -6
  270. package/dist/utils/multi-value-map.js +4 -4
  271. package/dist/utils/noop-modifier.js +1 -1
  272. package/dist/utils/position-provider.js +2 -1
  273. package/dist/utils/quotes.js +49 -43
  274. package/dist/utils/regexp.js +25 -18
  275. package/dist/utils/string.js +136 -104
  276. package/dist/utils/type-guards.js +2 -1
  277. package/dist/validator/constants.js +1 -1
  278. package/dist/validator/helpers.js +1 -1
  279. package/dist/validator/index.js +8 -8
  280. package/dist/validator/value.js +6 -6
  281. package/dist/version.js +2 -2
  282. package/package.json +3 -1
  283. package/dist/errors/binary-schema-mismatch-error.js +0 -37
  284. package/dist/types/errors/binary-schema-mismatch-error.d.ts +0 -23
@@ -1,20 +1,22 @@
1
1
  /*
2
- * AGTree v4.0.1 (build date: Thu, 19 Feb 2026 05:13:05 GMT)
2
+ * AGTree v4.0.3 (build date: Tue, 24 Mar 2026 15:29:20 GMT)
3
3
  * (c) 2026 Adguard Software Ltd.
4
4
  * Released under the MIT license
5
5
  * https://github.com/AdguardTeam/tsurlfilter/tree/master/packages/agtree#readme
6
6
  */
7
7
  /**
8
- * @file Conversion result interface and helper functions
8
+ * @file Conversion result interface and helper functions.
9
9
  */
10
10
  /**
11
11
  * Helper function to create a generic conversion result.
12
12
  *
13
- * @param result Conversion result
14
- * @param isConverted Indicates whether the input item was converted
15
- * @template T Type of the item to convert
16
- * @template U Type of the conversion result (defaults to `T`, but can be `T[]` as well)
17
- * @returns Generic conversion result
13
+ * @template T Type of the item to convert.
14
+ * @template U Type of the conversion result (defaults to `T`, but can be `T[]` as well).
15
+ *
16
+ * @param result Conversion result.
17
+ * @param isConverted Indicates whether the input item was converted.
18
+ *
19
+ * @returns Generic conversion result.
18
20
  */
19
21
  // eslint-disable-next-line max-len
20
22
  function createConversionResult(result, isConverted) {
@@ -26,10 +28,12 @@ function createConversionResult(result, isConverted) {
26
28
  /**
27
29
  * Helper function to create a node conversion result.
28
30
  *
29
- * @param nodes Array of nodes
30
- * @param isConverted Indicates whether the input item was converted
31
- * @template T Type of the node (extends `Node`)
32
- * @returns Node conversion result
31
+ * @template T Type of the node (extends `Node`).
32
+ *
33
+ * @param nodes Array of nodes.
34
+ * @param isConverted Indicates whether the input item was converted.
35
+ *
36
+ * @returns Node conversion result.
33
37
  */
34
38
  function createNodeConversionResult(nodes, isConverted) {
35
39
  return createConversionResult(nodes, isConverted);
@@ -1,5 +1,5 @@
1
1
  /*
2
- * AGTree v4.0.1 (build date: Thu, 19 Feb 2026 05:13:05 GMT)
2
+ * AGTree v4.0.3 (build date: Tue, 24 Mar 2026 15:29:20 GMT)
3
3
  * (c) 2026 Adguard Software Ltd.
4
4
  * Released under the MIT license
5
5
  * https://github.com/AdguardTeam/tsurlfilter/tree/master/packages/agtree#readme
@@ -8,25 +8,27 @@ import { NotImplementedError } from '../../errors/not-implemented-error.js';
8
8
  import { BaseConverter } from './base-converter.js';
9
9
 
10
10
  /**
11
- * @file Base class for rule converters
11
+ * @file Base class for rule converters.
12
12
  *
13
13
  * TS doesn't support abstract static methods, so we should use
14
- * a workaround and extend this class instead of implementing it
14
+ * a workaround and extend this class instead of implementing it.
15
15
  */
16
16
  /* eslint-disable jsdoc/require-returns-check */
17
17
  /* eslint-disable @typescript-eslint/no-unused-vars */
18
18
  /**
19
- * Basic class for rule converters
19
+ * Basic class for rule converters.
20
20
  */
21
21
  class RuleConverterBase extends BaseConverter {
22
22
  /**
23
23
  * Converts an adblock filtering rule to AdGuard format, if possible.
24
24
  *
25
- * @param rule Rule node to convert
25
+ * @param rule Rule node to convert.
26
+ *
26
27
  * @returns An object which follows the {@link NodeConversionResult} interface. Its `result` property contains
27
28
  * the array of converted rule nodes, and its `isConverted` flag indicates whether the original rule was converted.
28
- * If the rule was not converted, the result array will contain the original node with the same object reference
29
- * @throws If the rule is invalid or cannot be converted
29
+ * If the rule was not converted, the result array will contain the original node with the same object reference.
30
+ *
31
+ * @throws If the rule is invalid or cannot be converted.
30
32
  */
31
33
  static convertToAdg(rule) {
32
34
  throw new NotImplementedError();
@@ -34,11 +36,13 @@ class RuleConverterBase extends BaseConverter {
34
36
  /**
35
37
  * Converts an adblock filtering rule to Adblock Plus format, if possible.
36
38
  *
37
- * @param rule Rule node to convert
39
+ * @param rule Rule node to convert.
40
+ *
38
41
  * @returns An object which follows the {@link NodeConversionResult} interface. Its `result` property contains
39
42
  * the array of converted rule nodes, and its `isConverted` flag indicates whether the original rule was converted.
40
- * If the rule was not converted, the result array will contain the original node with the same object reference
41
- * @throws If the rule is invalid or cannot be converted
43
+ * If the rule was not converted, the result array will contain the original node with the same object reference.
44
+ *
45
+ * @throws If the rule is invalid or cannot be converted.
42
46
  */
43
47
  static convertToAbp(rule) {
44
48
  throw new NotImplementedError();
@@ -46,11 +50,13 @@ class RuleConverterBase extends BaseConverter {
46
50
  /**
47
51
  * Converts an adblock filtering rule to uBlock Origin format, if possible.
48
52
  *
49
- * @param rule Rule node to convert
53
+ * @param rule Rule node to convert.
54
+ *
50
55
  * @returns An object which follows the {@link NodeConversionResult} interface. Its `result` property contains
51
56
  * the array of converted rule nodes, and its `isConverted` flag indicates whether the original rule was converted.
52
- * If the rule was not converted, the result array will contain the original node with the same object reference
53
- * @throws If the rule is invalid or cannot be converted
57
+ * If the rule was not converted, the result array will contain the original node with the same object reference.
58
+ *
59
+ * @throws If the rule is invalid or cannot be converted.
54
60
  */
55
61
  static convertToUbo(rule) {
56
62
  throw new NotImplementedError();
@@ -1,32 +1,34 @@
1
1
  /*
2
- * AGTree v4.0.1 (build date: Thu, 19 Feb 2026 05:13:05 GMT)
2
+ * AGTree v4.0.3 (build date: Tue, 24 Mar 2026 15:29:20 GMT)
3
3
  * (c) 2026 Adguard Software Ltd.
4
4
  * Released under the MIT license
5
5
  * https://github.com/AdguardTeam/tsurlfilter/tree/master/packages/agtree#readme
6
6
  */
7
7
  import { CommentRuleType, CommentMarker } from '../../nodes/index.js';
8
- import { SPACE } from '../../utils/constants.js';
9
- import { RuleConverterBase } from '../base-interfaces/rule-converter-base.js';
10
8
  import { clone } from '../../utils/clone.js';
9
+ import { SPACE } from '../../utils/constants.js';
11
10
  import { createNodeConversionResult } from '../base-interfaces/conversion-result.js';
11
+ import { RuleConverterBase } from '../base-interfaces/rule-converter-base.js';
12
12
 
13
13
  /**
14
- * @file Comment rule converter
14
+ * @file Comment rule converter.
15
15
  */
16
16
  /**
17
- * Comment rule converter class
17
+ * Comment rule converter class.
18
18
  *
19
- * @todo Implement `convertToUbo` and `convertToAbp`
19
+ * @todo Implement `convertToUbo` and `convertToAbp`.
20
20
  */
21
21
  class CommentRuleConverter extends RuleConverterBase {
22
22
  /**
23
23
  * Converts a comment rule to AdGuard format, if possible.
24
24
  *
25
- * @param rule Rule node to convert
25
+ * @param rule Rule node to convert.
26
+ *
26
27
  * @returns An object which follows the {@link NodeConversionResult} interface. Its `result` property contains
27
28
  * the array of converted rule nodes, and its `isConverted` flag indicates whether the original rule was converted.
28
- * If the rule was not converted, the result array will contain the original node with the same object reference
29
- * @throws If the rule is invalid or cannot be converted
29
+ * If the rule was not converted, the result array will contain the original node with the same object reference.
30
+ *
31
+ * @throws If the rule is invalid or cannot be converted.
30
32
  */
31
33
  static convertToAdg(rule) {
32
34
  // TODO: Add support for other comment types, if needed
@@ -1,34 +1,36 @@
1
1
  /*
2
- * AGTree v4.0.1 (build date: Thu, 19 Feb 2026 05:13:05 GMT)
2
+ * AGTree v4.0.3 (build date: Tue, 24 Mar 2026 15:29:20 GMT)
3
3
  * (c) 2026 Adguard Software Ltd.
4
4
  * Released under the MIT license
5
5
  * https://github.com/AdguardTeam/tsurlfilter/tree/master/packages/agtree#readme
6
6
  */
7
7
  import { CosmeticRuleSeparator } from '../../nodes/index.js';
8
- import { RuleConverterBase } from '../base-interfaces/rule-converter-base.js';
9
- import { CssSelectorConverter } from '../css/index.js';
8
+ import { CssTokenStream } from '../../parser/css/css-token-stream.js';
10
9
  import { AdblockSyntax } from '../../utils/adblockers.js';
11
10
  import { clone } from '../../utils/clone.js';
12
11
  import { createNodeConversionResult } from '../base-interfaces/conversion-result.js';
13
- import { CssTokenStream } from '../../parser/css/css-token-stream.js';
12
+ import { RuleConverterBase } from '../base-interfaces/rule-converter-base.js';
13
+ import { CssSelectorConverter } from '../css/index.js';
14
14
 
15
15
  /**
16
- * @file CSS injection rule converter
16
+ * @file CSS injection rule converter.
17
17
  */
18
18
  /**
19
- * CSS injection rule converter class
19
+ * CSS injection rule converter class.
20
20
  *
21
- * @todo Implement `convertToUbo` and `convertToAbp`
21
+ * @todo Implement `convertToUbo` and `convertToAbp`.
22
22
  */
23
23
  class CssInjectionRuleConverter extends RuleConverterBase {
24
24
  /**
25
25
  * Converts a CSS injection rule to AdGuard format, if possible.
26
26
  *
27
- * @param rule Rule node to convert
27
+ * @param rule Rule node to convert.
28
+ *
28
29
  * @returns An object which follows the {@link NodeConversionResult} interface. Its `result` property contains
29
30
  * the array of converted rule nodes, and its `isConverted` flag indicates whether the original rule was converted.
30
- * If the rule was not converted, the result array will contain the original node with the same object reference
31
- * @throws If the rule is invalid or cannot be converted
31
+ * If the rule was not converted, the result array will contain the original node with the same object reference.
32
+ *
33
+ * @throws If the rule is invalid or cannot be converted.
32
34
  */
33
35
  static convertToAdg(rule) {
34
36
  const separator = rule.separator.value;
@@ -1,34 +1,36 @@
1
1
  /*
2
- * AGTree v4.0.1 (build date: Thu, 19 Feb 2026 05:13:05 GMT)
2
+ * AGTree v4.0.3 (build date: Tue, 24 Mar 2026 15:29:20 GMT)
3
3
  * (c) 2026 Adguard Software Ltd.
4
4
  * Released under the MIT license
5
5
  * https://github.com/AdguardTeam/tsurlfilter/tree/master/packages/agtree#readme
6
6
  */
7
7
  import { CosmeticRuleSeparator } from '../../nodes/index.js';
8
- import { RuleConverterBase } from '../base-interfaces/rule-converter-base.js';
9
- import { CssSelectorConverter } from '../css/index.js';
8
+ import { CssTokenStream } from '../../parser/css/css-token-stream.js';
10
9
  import { AdblockSyntax } from '../../utils/adblockers.js';
11
10
  import { clone } from '../../utils/clone.js';
12
11
  import { createNodeConversionResult } from '../base-interfaces/conversion-result.js';
13
- import { CssTokenStream } from '../../parser/css/css-token-stream.js';
12
+ import { RuleConverterBase } from '../base-interfaces/rule-converter-base.js';
13
+ import { CssSelectorConverter } from '../css/index.js';
14
14
 
15
15
  /**
16
- * @file Element hiding rule converter
16
+ * @file Element hiding rule converter.
17
17
  */
18
18
  /**
19
- * Element hiding rule converter class
19
+ * Element hiding rule converter class.
20
20
  *
21
- * @todo Implement `convertToUbo` and `convertToAbp`
21
+ * @todo Implement `convertToUbo` and `convertToAbp`.
22
22
  */
23
23
  class ElementHidingRuleConverter extends RuleConverterBase {
24
24
  /**
25
25
  * Converts an element hiding rule to AdGuard format, if possible.
26
26
  *
27
- * @param rule Rule node to convert
27
+ * @param rule Rule node to convert.
28
+ *
28
29
  * @returns An object which follows the {@link NodeConversionResult} interface. Its `result` property contains
29
30
  * the array of converted rule nodes, and its `isConverted` flag indicates whether the original rule was converted.
30
- * If the rule was not converted, the result array will contain the original node with the same object reference
31
- * @throws If the rule is invalid or cannot be converted
31
+ * If the rule was not converted, the result array will contain the original node with the same object reference.
32
+ *
33
+ * @throws If the rule is invalid or cannot be converted.
32
34
  */
33
35
  static convertToAdg(rule) {
34
36
  const separator = rule.separator.value;
@@ -1,42 +1,45 @@
1
1
  /*
2
- * AGTree v4.0.1 (build date: Thu, 19 Feb 2026 05:13:05 GMT)
2
+ * AGTree v4.0.3 (build date: Tue, 24 Mar 2026 15:29:20 GMT)
3
3
  * (c) 2026 Adguard Software Ltd.
4
4
  * Released under the MIT license
5
5
  * https://github.com/AdguardTeam/tsurlfilter/tree/master/packages/agtree#readme
6
6
  */
7
+ import { createModifierListNode, createModifierNode } from '../../ast-utils/modifiers.js';
8
+ import { createNetworkRuleNode } from '../../ast-utils/network-rules.js';
9
+ import { isUboResponseHeaderRemovalRuleBody } from '../../common/ubo-html-filtering-body-common.js';
7
10
  import { RuleConversionError } from '../../errors/rule-conversion-error.js';
8
11
  import { RuleCategory, CosmeticRuleType } from '../../nodes/index.js';
9
- import { RuleConverterBase } from '../base-interfaces/rule-converter-base.js';
10
- import { createModifierListNode, createModifierNode } from '../../ast-utils/modifiers.js';
12
+ import { UboHtmlFilteringBodyParser } from '../../parser/cosmetic/html-filtering-body/ubo-html-filtering-body-parser.js';
13
+ import { AdblockSyntax } from '../../utils/adblockers.js';
11
14
  import { EMPTY } from '../../utils/constants.js';
12
15
  import { ADBLOCK_URL_START, ADBLOCK_URL_SEPARATOR } from '../../utils/regexp.js';
13
- import { createNetworkRuleNode } from '../../ast-utils/network-rules.js';
14
- import { AdblockSyntax } from '../../utils/adblockers.js';
15
16
  import { createNodeConversionResult } from '../base-interfaces/conversion-result.js';
16
- import { isUboResponseHeaderRemovalRuleBody } from '../../common/ubo-html-filtering-body-common.js';
17
- import { UboHtmlFilteringBodyParser } from '../../parser/cosmetic/html-filtering-body/ubo-html-filtering-body-parser.js';
17
+ import { RuleConverterBase } from '../base-interfaces/rule-converter-base.js';
18
18
 
19
19
  /**
20
- * @file Converter for request header removal rules
20
+ * @file Converter for request header removal rules.
21
21
  */
22
22
  const ADG_REMOVEHEADER_MODIFIER = 'removeheader';
23
23
  const ERROR_MESSAGES = {
24
24
  MULTIPLE_DOMAINS_NOT_SUPPORTED: 'Multiple domains are not supported yet',
25
25
  };
26
26
  /**
27
- * Converter for request header removal rules
27
+ * Converter for request header removal rules.
28
28
  *
29
- * @todo Implement `convertToUbo` (ABP currently doesn't support header removal rules)
29
+ * @todo Implement `convertToUbo` (ABP currently doesn't support header removal rules).
30
30
  */
31
31
  class HeaderRemovalRuleConverter extends RuleConverterBase {
32
32
  /**
33
33
  * Converts a header removal rule to AdGuard syntax, if possible.
34
34
  *
35
- * @param rule Rule node to convert
35
+ * @param rule Rule node to convert.
36
+ *
36
37
  * @returns An object which follows the {@link NodeConversionResult} interface. Its `result` property contains
37
38
  * the array of converted rule nodes, and its `isConverted` flag indicates whether the original rule was converted.
38
- * If the rule was not converted, the result array will contain the original node with the same object reference
39
- * @throws If the rule is invalid or cannot be converted
39
+ * If the rule was not converted, the result array will contain the original node with the same object reference.
40
+ *
41
+ * @throws If the rule is invalid or cannot be converted.
42
+ *
40
43
  * @example
41
44
  * If the input rule is:
42
45
  * ```adblock
@@ -1,25 +1,25 @@
1
1
  /*
2
- * AGTree v4.0.1 (build date: Thu, 19 Feb 2026 05:13:05 GMT)
2
+ * AGTree v4.0.3 (build date: Tue, 24 Mar 2026 15:29:20 GMT)
3
3
  * (c) 2026 Adguard Software Ltd.
4
4
  * Released under the MIT license
5
5
  * https://github.com/AdguardTeam/tsurlfilter/tree/master/packages/agtree#readme
6
6
  */
7
7
  import { sprintf } from 'sprintf-js';
8
+ import { cloneDomainListNode } from '../../ast-utils/clone.js';
9
+ import { RuleConversionError } from '../../errors/rule-conversion-error.js';
10
+ import { AdgHtmlFilteringBodyGenerator } from '../../generator/cosmetic/html-filtering-body/adg-html-filtering-body-generator.js';
11
+ import { UboHtmlFilteringBodyGenerator } from '../../generator/cosmetic/html-filtering-body/ubo-html-filtering-body-generator.js';
8
12
  import { CosmeticRuleSeparator, CosmeticRuleType, RuleCategory } from '../../nodes/index.js';
13
+ import { AdgHtmlFilteringBodyParser } from '../../parser/cosmetic/html-filtering-body/adg-html-filtering-body-parser.js';
14
+ import { UboHtmlFilteringBodyParser } from '../../parser/cosmetic/html-filtering-body/ubo-html-filtering-body-parser.js';
9
15
  import { AdblockSyntax } from '../../utils/adblockers.js';
10
- import { RuleConversionError } from '../../errors/rule-conversion-error.js';
11
- import { RuleConverterBase } from '../base-interfaces/rule-converter-base.js';
12
- import { createNodeConversionResult } from '../base-interfaces/conversion-result.js';
13
- import { cloneDomainListNode } from '../../ast-utils/clone.js';
14
16
  import { EMPTY, EQUALS } from '../../utils/constants.js';
15
17
  import { RegExpUtils } from '../../utils/regexp.js';
16
- import { AdgHtmlFilteringBodyParser } from '../../parser/cosmetic/html-filtering-body/adg-html-filtering-body-parser.js';
17
- import { UboHtmlFilteringBodyParser } from '../../parser/cosmetic/html-filtering-body/ubo-html-filtering-body-parser.js';
18
- import { AdgHtmlFilteringBodyGenerator } from '../../generator/cosmetic/html-filtering-body/adg-html-filtering-body-generator.js';
19
- import { UboHtmlFilteringBodyGenerator } from '../../generator/cosmetic/html-filtering-body/ubo-html-filtering-body-generator.js';
18
+ import { createNodeConversionResult } from '../base-interfaces/conversion-result.js';
19
+ import { RuleConverterBase } from '../base-interfaces/rule-converter-base.js';
20
20
 
21
21
  /**
22
- * @file HTML filtering rule converter
22
+ * @file HTML filtering rule converter.
23
23
  */
24
24
  /**
25
25
  * From the AdGuard docs:
@@ -109,9 +109,9 @@ const ERROR_MESSAGES = {
109
109
  SPECIAL_PSEUDO_CLASS_SELECTOR_NOT_SUPPORTED: "Special pseudo-class selector '%s' is not supported in conversion",
110
110
  };
111
111
  /**
112
- * HTML filtering rule converter class
112
+ * HTML filtering rule converter class.
113
113
  *
114
- * @todo Implement `convertToUbo` (ABP currently doesn't support HTML filtering rules)
114
+ * @todo Implement `convertToUbo` (ABP currently doesn't support HTML filtering rules).
115
115
  */
116
116
  class HtmlRuleConverter extends RuleConverterBase {
117
117
  /**
@@ -138,7 +138,7 @@ class HtmlRuleConverter extends RuleConverterBase {
138
138
  * Mark rule as converted in ADG -> ADG conversion only if
139
139
  * special attribute selectors are present in the rule body,
140
140
  * because they are deprecated and will be removed soon,
141
- * so we convert them to pseudo-class selectors
141
+ * so we convert them to pseudo-class selectors.
142
142
  */
143
143
  isConverted = true;
144
144
  return HtmlRuleConverter.convertSpecialAttributeSelectorAdgToAdg(name, value);
@@ -158,7 +158,7 @@ class HtmlRuleConverter extends RuleConverterBase {
158
158
  throw new RuleConversionError(ERROR_MESSAGES.ABP_NOT_SUPPORTED);
159
159
  }
160
160
  // Convert body
161
- const convertedBody = HtmlRuleConverter.convertBody(rule.body, parser, AdgHtmlFilteringBodyGenerator, onSpecialAttributeSelector, onSpecialPseudoClassSelector);
161
+ const convertedBody = HtmlRuleConverter.convertBody(rule.body, parser, AdgHtmlFilteringBodyGenerator, onSpecialAttributeSelector, onSpecialPseudoClassSelector, rule.syntax === AdblockSyntax.Adg);
162
162
  if (!isConverted) {
163
163
  return createNodeConversionResult([rule], false);
164
164
  }
@@ -222,9 +222,9 @@ class HtmlRuleConverter extends RuleConverterBase {
222
222
  * - `[wildcard="*content*"]` -> `:contains(/*.content*./s)`
223
223
  * convert search pattern to regular expression
224
224
  * - `[min-length="min"]` -> `:contains(/^(?=.{min,}$).*\/s)`
225
- * converts to a length-matching regular expression
225
+ * converts to a length-matching regular expression.
226
226
  * - `[max-length="max"]` -> `:contains(/^(?=.{0,max}$).*\/s)`
227
- * converts to a length-matching regular expression
227
+ * converts to a length-matching regular expression.
228
228
  *
229
229
  * Note: This attribute selector to pseudo-class selector conversion
230
230
  * is needed because AdGuard special attribute selectors are going
@@ -302,7 +302,7 @@ class HtmlRuleConverter extends RuleConverterBase {
302
302
  * - `:has-text(text)` -> `:contains(text)`
303
303
  * direct conversion, no changes to argument
304
304
  * - `:min-text-length(min)` -> `:contains(/^(?=.{min,MAX_CONVERSION_DEFAULT}$).*\/s)`
305
- * converts to a length-matching regular expression
305
+ * converts to a length-matching regular expression.
306
306
  *
307
307
  * @param name Name of the special pseudo-class selector.
308
308
  * @param argument Argument of the special pseudo-class selector.
@@ -345,7 +345,7 @@ class HtmlRuleConverter extends RuleConverterBase {
345
345
  * convert search pattern to regular expression
346
346
  * - `[min-length="min"]` -> `:min-text-length(min)`
347
347
  * direct conversion, no changes to value
348
- * - `[max-length]` is skipped
348
+ * - `[max-length]` is skipped.
349
349
  *
350
350
  * @param name Name of the special attribute selector.
351
351
  * @param value Value of the special attribute selector.
@@ -384,7 +384,7 @@ class HtmlRuleConverter extends RuleConverterBase {
384
384
  /**
385
385
  * Handles special pseudo-class selectors during AdGuard to uBlock conversion:
386
386
  * - `:contains(text)` -> `:has-text(text)`
387
- * direct conversion, no changes to argument
387
+ * direct conversion, no changes to argument.
388
388
  *
389
389
  * @param name Name of the special pseudo-class selector.
390
390
  * @param argument Argument of the special pseudo-class selector.
@@ -411,6 +411,70 @@ class HtmlRuleConverter extends RuleConverterBase {
411
411
  }
412
412
  }
413
413
  }
414
+ /**
415
+ * Pre-scans a complex selector's child selectors
416
+ * for {@link AdgAttributeSelectors.MinLength}
417
+ * and {@link AdgAttributeSelectors.MaxLength} attribute selectors.
418
+ *
419
+ * Resolves duplicates to the most *restrictive* value:
420
+ * - for multiple `[min-length]` selectors, the largest value is selected;
421
+ * - for multiple `[max-length]` selectors, the smallest value is selected.
422
+ *
423
+ * Logs a warning when duplicate length selectors are found.
424
+ *
425
+ * @param selectors Child selectors of a complex selector to scan.
426
+ *
427
+ * @returns Resolved length constraints,
428
+ * or `null` if no length selectors were found.
429
+ */
430
+ static collectLengthConstraints(selectors) {
431
+ const minValues = [];
432
+ const maxValues = [];
433
+ for (let i = 0; i < selectors.length; i += 1) {
434
+ const selector = selectors[i];
435
+ if (selector.type !== 'AttributeSelector') {
436
+ continue;
437
+ }
438
+ const { value: name } = selector.name;
439
+ if (name !== AdgAttributeSelectors.MinLength
440
+ && name !== AdgAttributeSelectors.MaxLength) {
441
+ continue;
442
+ }
443
+ if (!('value' in selector) || selector.value.value === EMPTY) {
444
+ continue;
445
+ }
446
+ const { value } = selector.value;
447
+ HtmlRuleConverter.assertValidLengthValue(name, value, ERROR_MESSAGES.SPECIAL_ATTRIBUTE_SELECTOR_VALUE_INT, ERROR_MESSAGES.SPECIAL_ATTRIBUTE_SELECTOR_VALUE_POSITIVE);
448
+ if (name === AdgAttributeSelectors.MinLength) {
449
+ minValues.push(Number(value));
450
+ }
451
+ else {
452
+ maxValues.push(Number(value));
453
+ }
454
+ }
455
+ if (minValues.length === 0 && maxValues.length === 0) {
456
+ return null;
457
+ }
458
+ let min = null;
459
+ let max = null;
460
+ if (minValues.length > 1) {
461
+ min = Math.max(...minValues);
462
+ // eslint-disable-next-line no-console
463
+ console.warn(`Multiple [min-length] selectors found among: [${minValues.join(', ')}]. Selected largest: ${min}.`);
464
+ }
465
+ else if (minValues.length === 1) {
466
+ [min] = minValues;
467
+ }
468
+ if (maxValues.length > 1) {
469
+ max = Math.min(...maxValues);
470
+ // eslint-disable-next-line no-console
471
+ console.warn(`Multiple [max-length] selectors found among: [${maxValues.join(', ')}]. Selected smallest: ${max}.`);
472
+ }
473
+ else if (maxValues.length === 1) {
474
+ [max] = maxValues;
475
+ }
476
+ return { min, max };
477
+ }
414
478
  /**
415
479
  * Converts a HTML filtering rule body by handling special simple selectors via callbacks.
416
480
  * Special simple selectors are skipped in the converted selector list and should be handled from callee.
@@ -420,10 +484,13 @@ class HtmlRuleConverter extends RuleConverterBase {
420
484
  * @param generator HTML filtering rule body generator used for generating raw value bodies.
421
485
  * @param onSpecialAttributeSelector Callback invoked when a special attribute selector is found.
422
486
  * @param onSpecialPseudoClassSelector Callback invoked when a special pseudo-class selector is found.
487
+ * @param shouldMergeLengthSelectors If true, `[min-length]` and `[max-length]` attribute
488
+ * selectors within the same complex selector are merged into a single `:contains()` pseudo-class.
489
+ * Defaults to `false`.
423
490
  *
424
491
  * @returns Converted selector list without special simple selectors.
425
492
  */
426
- static convertBody(body, parser, generator, onSpecialAttributeSelector, onSpecialPseudoClassSelector) {
493
+ static convertBody(body, parser, generator, onSpecialAttributeSelector, onSpecialPseudoClassSelector, shouldMergeLengthSelectors = false) {
427
494
  // Handle case when body is raw value string.
428
495
  // If so, parse it first as we need to work with AST nodes.
429
496
  let processedBody;
@@ -445,6 +512,11 @@ class HtmlRuleConverter extends RuleConverterBase {
445
512
  const { children: selectors } = complexSelectors[i];
446
513
  // Complex selector node must not be empty
447
514
  HtmlRuleConverter.assertNotEmpty(selectors, ERROR_MESSAGES.EMPTY_COMPLEX_SELECTOR);
515
+ // Pre-scan for [min-length] / [max-length] constraints to merge them into one :contains()
516
+ const lengthConstraints = shouldMergeLengthSelectors
517
+ ? HtmlRuleConverter.collectLengthConstraints(selectors)
518
+ : null;
519
+ let lengthContainsEmitted = false;
448
520
  // Convert each selector
449
521
  const convertedSelectors = [];
450
522
  for (let j = 0; j < selectors.length; j += 1) {
@@ -482,6 +554,21 @@ class HtmlRuleConverter extends RuleConverterBase {
482
554
  }
483
555
  const name = selector.name.value;
484
556
  const { value } = selector.value;
557
+ // Merge [min-length] and [max-length] into a single :contains() (ADG→ADG)
558
+ if (lengthConstraints !== null
559
+ && (name === AdgAttributeSelectors.MinLength
560
+ || name === AdgAttributeSelectors.MaxLength)) {
561
+ if (!lengthContainsEmitted) {
562
+ // Invoke the callback once to trigger its side effects
563
+ // (e.g. the isConverted flag in convertToAdg), but discard
564
+ // the individual :contains() it returns — we emit the
565
+ // merged one instead.
566
+ onSpecialAttributeSelector(name, value);
567
+ convertedSelectors.push(HtmlRuleConverter.getPseudoClassSelectorNode(AdgPseudoClasses.Contains, RegExpUtils.getLengthRegexp(lengthConstraints.min, lengthConstraints.max)));
568
+ lengthContainsEmitted = true;
569
+ }
570
+ continue;
571
+ }
485
572
  // Invoke callback and:
486
573
  // - add returned simple selector if it's not boolean
487
574
  // - skip adding if returned value is false
@@ -1,48 +1,50 @@
1
1
  /*
2
- * AGTree v4.0.1 (build date: Thu, 19 Feb 2026 05:13:05 GMT)
2
+ * AGTree v4.0.3 (build date: Tue, 24 Mar 2026 15:29:20 GMT)
3
3
  * (c) 2026 Adguard Software Ltd.
4
4
  * Released under the MIT license
5
5
  * https://github.com/AdguardTeam/tsurlfilter/tree/master/packages/agtree#readme
6
6
  */
7
- import { CosmeticRuleType, RuleCategory, CosmeticRuleSeparator } from '../../nodes/index.js';
8
- import { AdblockSyntax } from '../../utils/adblockers.js';
9
- import { HtmlRuleConverter } from './html.js';
10
- import { ScriptletRuleConverter } from './scriptlet.js';
11
7
  import { RuleConversionError } from '../../errors/rule-conversion-error.js';
12
- import { RuleConverterBase } from '../base-interfaces/rule-converter-base.js';
13
- import { AdgCosmeticRuleModifierConverter } from './rule-modifiers/adg.js';
14
- import { CssInjectionRuleConverter } from './css.js';
15
- import { ElementHidingRuleConverter } from './element-hiding.js';
16
- import { HeaderRemovalRuleConverter } from './header-removal.js';
17
- import { createNodeConversionResult } from '../base-interfaces/conversion-result.js';
18
- import { UboCosmeticRuleModifierConverter } from './rule-modifiers/ubo.js';
19
- import { clone } from '../../utils/clone.js';
8
+ import { CosmeticRuleType, RuleCategory, CosmeticRuleSeparator } from '../../nodes/index.js';
20
9
  import { COMMA } from '../../utils/constants.js';
10
+ import { AdblockSyntax } from '../../utils/adblockers.js';
21
11
  import 'tldts';
22
12
  import 'glob-to-regexp';
23
- import 'sprintf-js';
24
13
  import '@adguard/css-tokenizer';
14
+ import 'sprintf-js';
25
15
  import 'json5';
26
- import '../../parser/css/balancing.js';
27
16
  import '../data/css.js';
17
+ import '../../parser/css/balancing.js';
18
+ import { clone } from '../../utils/clone.js';
19
+ import { createNodeConversionResult } from '../base-interfaces/conversion-result.js';
20
+ import { RuleConverterBase } from '../base-interfaces/rule-converter-base.js';
21
+ import { CssInjectionRuleConverter } from './css.js';
22
+ import { ElementHidingRuleConverter } from './element-hiding.js';
23
+ import { HeaderRemovalRuleConverter } from './header-removal.js';
24
+ import { HtmlRuleConverter } from './html.js';
25
+ import { AdgCosmeticRuleModifierConverter } from './rule-modifiers/adg.js';
26
+ import { UboCosmeticRuleModifierConverter } from './rule-modifiers/ubo.js';
27
+ import { ScriptletRuleConverter } from './scriptlet.js';
28
28
 
29
29
  /**
30
- * @file Cosmetic rule converter
30
+ * @file Cosmetic rule converter.
31
31
  */
32
32
  /**
33
- * Cosmetic rule converter class (also known as "non-basic rule converter")
33
+ * Cosmetic rule converter class (also known as "non-basic rule converter").
34
34
  *
35
- * @todo Implement `convertToUbo` and `convertToAbp`
35
+ * @todo Implement `convertToUbo` and `convertToAbp`.
36
36
  */
37
37
  class CosmeticRuleConverter extends RuleConverterBase {
38
38
  /**
39
39
  * Converts a cosmetic rule to AdGuard syntax, if possible.
40
40
  *
41
- * @param rule Rule node to convert
41
+ * @param rule Rule node to convert.
42
+ *
42
43
  * @returns An object which follows the {@link NodeConversionResult} interface. Its `result` property contains
43
44
  * the array of converted rule nodes, and its `isConverted` flag indicates whether the original rule was converted.
44
- * If the rule was not converted, the result array will contain the original node with the same object reference
45
- * @throws If the rule is invalid or cannot be converted
45
+ * If the rule was not converted, the result array will contain the original node with the same object reference.
46
+ *
47
+ * @throws If the rule is invalid or cannot be converted.
46
48
  */
47
49
  static convertToAdg(rule) {
48
50
  let subconverterResult;
@@ -105,11 +107,13 @@ class CosmeticRuleConverter extends RuleConverterBase {
105
107
  /**
106
108
  * Converts a cosmetic rule to uBlock Origin syntax, if possible.
107
109
  *
108
- * @param rule Rule node to convert
110
+ * @param rule Rule node to convert.
111
+ *
109
112
  * @returns An object which follows the {@link NodeConversionResult} interface. Its `result` property contains
110
113
  * the array of converted rule nodes, and its `isConverted` flag indicates whether the original rule was converted.
111
- * If the rule was not converted, the result array will contain the original node with the same object reference
112
- * @throws If the rule is invalid or cannot be converted
114
+ * If the rule was not converted, the result array will contain the original node with the same object reference.
115
+ *
116
+ * @throws If the rule is invalid or cannot be converted.
113
117
  */
114
118
  static convertToUbo(rule) {
115
119
  // Skip conversation if the rule is already in uBO format