@browserless.io/browserless 2.31.1 → 2.32.0-beta-1

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 (432) hide show
  1. package/build/routes/chrome/http/content.post.body.json +8 -8
  2. package/build/routes/chrome/http/pdf.post.body.json +8 -8
  3. package/build/routes/chrome/http/scrape.post.body.json +8 -8
  4. package/build/routes/chrome/http/screenshot.post.body.json +8 -8
  5. package/build/routes/chromium/http/content.post.body.json +8 -8
  6. package/build/routes/chromium/http/pdf.post.body.json +8 -8
  7. package/build/routes/chromium/http/scrape.post.body.json +8 -8
  8. package/build/routes/chromium/http/screenshot.post.body.json +8 -8
  9. package/build/routes/edge/http/content.post.body.json +8 -8
  10. package/build/routes/edge/http/pdf.post.body.json +8 -8
  11. package/build/routes/edge/http/scrape.post.body.json +8 -8
  12. package/build/routes/edge/http/screenshot.post.body.json +8 -8
  13. package/build/routes/management/tests/management.spec.js +14 -0
  14. package/build/server.js +4 -5
  15. package/build/shared/utils/enjoi-resolver.d.ts +77 -0
  16. package/build/shared/utils/enjoi-resolver.js +399 -0
  17. package/docker/base/Dockerfile +2 -2
  18. package/extensions/ublocklite/README.md +4 -2
  19. package/extensions/ublocklite/_locales/ar/messages.json +34 -10
  20. package/extensions/ublocklite/_locales/az/messages.json +26 -2
  21. package/extensions/ublocklite/_locales/be/messages.json +26 -2
  22. package/extensions/ublocklite/_locales/bg/messages.json +26 -2
  23. package/extensions/ublocklite/_locales/bn/messages.json +26 -2
  24. package/extensions/ublocklite/_locales/br_FR/messages.json +26 -2
  25. package/extensions/ublocklite/_locales/bs/messages.json +26 -2
  26. package/extensions/ublocklite/_locales/ca/messages.json +26 -2
  27. package/extensions/ublocklite/_locales/cs/messages.json +26 -2
  28. package/extensions/ublocklite/_locales/cv/messages.json +26 -2
  29. package/extensions/ublocklite/_locales/cy/messages.json +37 -13
  30. package/extensions/ublocklite/_locales/da/messages.json +26 -2
  31. package/extensions/ublocklite/_locales/de/messages.json +26 -2
  32. package/extensions/ublocklite/_locales/el/messages.json +29 -5
  33. package/extensions/ublocklite/_locales/en/messages.json +26 -2
  34. package/extensions/ublocklite/_locales/en_GB/messages.json +26 -2
  35. package/extensions/ublocklite/_locales/eo/messages.json +26 -2
  36. package/extensions/ublocklite/_locales/es/messages.json +26 -2
  37. package/extensions/ublocklite/_locales/et/messages.json +26 -2
  38. package/extensions/ublocklite/_locales/eu/messages.json +26 -2
  39. package/extensions/ublocklite/_locales/fa/messages.json +26 -2
  40. package/extensions/ublocklite/_locales/fi/messages.json +26 -2
  41. package/extensions/ublocklite/_locales/fil/messages.json +68 -44
  42. package/extensions/ublocklite/_locales/fr/messages.json +26 -2
  43. package/extensions/ublocklite/_locales/fy/messages.json +26 -2
  44. package/extensions/ublocklite/_locales/gl/messages.json +27 -3
  45. package/extensions/ublocklite/_locales/gu/messages.json +26 -2
  46. package/extensions/ublocklite/_locales/he/messages.json +26 -2
  47. package/extensions/ublocklite/_locales/hi/messages.json +26 -2
  48. package/extensions/ublocklite/_locales/hr/messages.json +26 -2
  49. package/extensions/ublocklite/_locales/hu/messages.json +26 -2
  50. package/extensions/ublocklite/_locales/hy/messages.json +26 -2
  51. package/extensions/ublocklite/_locales/id/messages.json +37 -13
  52. package/extensions/ublocklite/_locales/it/messages.json +26 -2
  53. package/extensions/ublocklite/_locales/ja/messages.json +26 -2
  54. package/extensions/ublocklite/_locales/ka/messages.json +26 -2
  55. package/extensions/ublocklite/_locales/kk/messages.json +26 -2
  56. package/extensions/ublocklite/_locales/kn/messages.json +26 -2
  57. package/extensions/ublocklite/_locales/ko/messages.json +26 -2
  58. package/extensions/ublocklite/_locales/lt/messages.json +26 -2
  59. package/extensions/ublocklite/_locales/lv/messages.json +26 -2
  60. package/extensions/ublocklite/_locales/mk/messages.json +26 -2
  61. package/extensions/ublocklite/_locales/ml/messages.json +26 -2
  62. package/extensions/ublocklite/_locales/mr/messages.json +26 -2
  63. package/extensions/ublocklite/_locales/ms/messages.json +26 -2
  64. package/extensions/ublocklite/_locales/nb/messages.json +26 -2
  65. package/extensions/ublocklite/_locales/nl/messages.json +26 -2
  66. package/extensions/ublocklite/_locales/oc/messages.json +26 -2
  67. package/extensions/ublocklite/_locales/pa/messages.json +26 -2
  68. package/extensions/ublocklite/_locales/pl/messages.json +26 -2
  69. package/extensions/ublocklite/_locales/pt_BR/messages.json +26 -2
  70. package/extensions/ublocklite/_locales/pt_PT/messages.json +29 -5
  71. package/extensions/ublocklite/_locales/ro/messages.json +26 -2
  72. package/extensions/ublocklite/_locales/ru/messages.json +26 -2
  73. package/extensions/ublocklite/_locales/si/messages.json +26 -2
  74. package/extensions/ublocklite/_locales/sk/messages.json +26 -2
  75. package/extensions/ublocklite/_locales/sl/messages.json +26 -2
  76. package/extensions/ublocklite/_locales/so/messages.json +26 -2
  77. package/extensions/ublocklite/_locales/sq/messages.json +26 -2
  78. package/extensions/ublocklite/_locales/sr/messages.json +26 -2
  79. package/extensions/ublocklite/_locales/sv/messages.json +26 -2
  80. package/extensions/ublocklite/_locales/sw/messages.json +26 -2
  81. package/extensions/ublocklite/_locales/ta/messages.json +26 -2
  82. package/extensions/ublocklite/_locales/te/messages.json +26 -2
  83. package/extensions/ublocklite/_locales/th/messages.json +26 -2
  84. package/extensions/ublocklite/_locales/tr/messages.json +26 -2
  85. package/extensions/ublocklite/_locales/uk/messages.json +26 -2
  86. package/extensions/ublocklite/_locales/ur/messages.json +26 -2
  87. package/extensions/ublocklite/_locales/vi/messages.json +33 -9
  88. package/extensions/ublocklite/_locales/zh_CN/messages.json +33 -9
  89. package/extensions/ublocklite/_locales/zh_TW/messages.json +26 -2
  90. package/extensions/ublocklite/css/develop.css +59 -25
  91. package/extensions/ublocklite/css/line-hor-dashed.png +0 -0
  92. package/extensions/ublocklite/dashboard.html +25 -16
  93. package/extensions/ublocklite/js/admin.js +7 -8
  94. package/extensions/ublocklite/js/background.js +38 -19
  95. package/extensions/ublocklite/js/dashboard.js +3 -3
  96. package/extensions/ublocklite/js/develop.js +533 -798
  97. package/extensions/ublocklite/js/dnr-editor.js +180 -0
  98. package/extensions/ublocklite/js/dnr-parser.js +30 -10
  99. package/extensions/ublocklite/js/i18n.js +5 -0
  100. package/extensions/ublocklite/js/mode-editor.js +87 -0
  101. package/extensions/ublocklite/js/mode-manager.js +11 -48
  102. package/extensions/ublocklite/js/mode-parser.js +211 -0
  103. package/extensions/ublocklite/js/ro-dnr-editor.js +95 -0
  104. package/extensions/ublocklite/js/ruleset-manager.js +42 -16
  105. package/extensions/ublocklite/js/rw-dnr-editor.js +391 -0
  106. package/extensions/ublocklite/js/settings.js +7 -71
  107. package/extensions/ublocklite/lib/codemirror/cm6.bundle.ubol.min.js +1 -1
  108. package/extensions/ublocklite/lib/codemirror/codemirror.LICENSE +21 -0
  109. package/extensions/ublocklite/manifest.json +1 -1
  110. package/extensions/ublocklite/rulesets/generic-details.json +3 -24
  111. package/extensions/ublocklite/rulesets/main/adguard-mobile.json +7 -18
  112. package/extensions/ublocklite/rulesets/main/annoyances-cookies.json +12 -6
  113. package/extensions/ublocklite/rulesets/main/annoyances-others.json +4 -2
  114. package/extensions/ublocklite/rulesets/main/annoyances-overlays.json +2 -1
  115. package/extensions/ublocklite/rulesets/main/annoyances-social.json +4 -2
  116. package/extensions/ublocklite/rulesets/main/block-lan.json +6 -0
  117. package/extensions/ublocklite/rulesets/main/chn-0.json +26 -64
  118. package/extensions/ublocklite/rulesets/main/cze-0.json +2 -1
  119. package/extensions/ublocklite/rulesets/main/deu-0.json +3 -1
  120. package/extensions/ublocklite/rulesets/main/dpollock-0.json +2 -0
  121. package/extensions/ublocklite/rulesets/main/easylist.json +23 -9
  122. package/extensions/ublocklite/rulesets/main/easyprivacy.json +40 -11
  123. package/extensions/ublocklite/rulesets/main/fin-0.json +11 -2
  124. package/extensions/ublocklite/rulesets/main/fra-0.json +22 -41
  125. package/extensions/ublocklite/rulesets/main/grc-0.json +1 -1
  126. package/extensions/ublocklite/rulesets/main/hun-0.json +9 -2
  127. package/extensions/ublocklite/rulesets/main/idn-0.json +8 -38
  128. package/extensions/ublocklite/rulesets/main/ind-0.json +35 -6
  129. package/extensions/ublocklite/rulesets/main/irn-0.json +1 -0
  130. package/extensions/ublocklite/rulesets/main/isr-0.json +11 -1
  131. package/extensions/ublocklite/rulesets/main/ita-0.json +1 -1
  132. package/extensions/ublocklite/rulesets/main/jpn-1.json +24 -18
  133. package/extensions/ublocklite/rulesets/main/kor-1.json +6 -4
  134. package/extensions/ublocklite/rulesets/main/nld-0.json +3 -2
  135. package/extensions/ublocklite/rulesets/main/nor-0.json +8 -2
  136. package/extensions/ublocklite/rulesets/main/pgl.json +10 -7
  137. package/extensions/ublocklite/rulesets/main/pol-0.json +5 -0
  138. package/extensions/ublocklite/rulesets/main/rus-0.json +30 -28
  139. package/extensions/ublocklite/rulesets/main/spa-1.json +18 -61
  140. package/extensions/ublocklite/rulesets/main/stevenblack-hosts.json +7223 -999
  141. package/extensions/ublocklite/rulesets/main/swe-1.json +40 -28
  142. package/extensions/ublocklite/rulesets/main/tur-0.json +17 -38
  143. package/extensions/ublocklite/rulesets/main/ublock-badware.json +28 -63
  144. package/extensions/ublocklite/rulesets/main/ublock-filters.json +173 -28
  145. package/extensions/ublocklite/rulesets/main/ukr-0.json +8 -26
  146. package/extensions/ublocklite/rulesets/main/urlhaus-full.json +339 -766
  147. package/extensions/ublocklite/rulesets/main/vie-1.json +33 -30
  148. package/extensions/ublocklite/rulesets/modify-headers/chn-0.json +4 -1
  149. package/extensions/ublocklite/rulesets/modify-headers/fra-0.json +0 -3
  150. package/extensions/ublocklite/rulesets/modify-headers/rus-0.json +2 -1
  151. package/extensions/ublocklite/rulesets/modify-headers/ublock-filters.json +1 -1
  152. package/extensions/ublocklite/rulesets/redirect/adguard-mobile.json +1 -1
  153. package/extensions/ublocklite/rulesets/redirect/annoyances-overlays.json +1 -0
  154. package/extensions/ublocklite/rulesets/redirect/spa-1.json +3 -4
  155. package/extensions/ublocklite/rulesets/redirect/swe-1.json +2 -1
  156. package/extensions/ublocklite/rulesets/redirect/tur-0.json +1 -1
  157. package/extensions/ublocklite/rulesets/redirect/ublock-filters.json +15 -5
  158. package/extensions/ublocklite/rulesets/redirect/vie-1.json +2 -2
  159. package/extensions/ublocklite/rulesets/regex/adguard-mobile.json +13 -0
  160. package/extensions/ublocklite/rulesets/regex/chn-0.json +2 -3
  161. package/extensions/ublocklite/rulesets/regex/jpn-1.json +1 -1
  162. package/extensions/ublocklite/rulesets/regex/kor-1.json +1 -0
  163. package/extensions/ublocklite/rulesets/regex/nor-0.json +10 -0
  164. package/extensions/ublocklite/rulesets/regex/spa-0.json +0 -1
  165. package/extensions/ublocklite/rulesets/regex/spa-1.json +0 -13
  166. package/extensions/ublocklite/rulesets/regex/ublock-badware.json +5 -6
  167. package/extensions/ublocklite/rulesets/regex/ublock-filters.json +14 -6
  168. package/extensions/ublocklite/rulesets/regex/ukr-0.json +2 -2
  169. package/extensions/ublocklite/rulesets/removeparam/adguard-spyware-url.json +10 -5
  170. package/extensions/ublocklite/rulesets/removeparam/rus-0.json +1 -1
  171. package/extensions/ublocklite/rulesets/removeparam/rus-1.json +3 -2
  172. package/extensions/ublocklite/rulesets/ruleset-details.json +246 -246
  173. package/extensions/ublocklite/rulesets/scripting/declarative/adguard-mobile.js +3 -3
  174. package/extensions/ublocklite/rulesets/scripting/declarative/annoyances-cookies.js +1 -1
  175. package/extensions/ublocklite/rulesets/scripting/declarative/annoyances-others.js +3 -3
  176. package/extensions/ublocklite/rulesets/scripting/declarative/annoyances-overlays.js +1 -1
  177. package/extensions/ublocklite/rulesets/scripting/declarative/chn-0.js +3 -3
  178. package/extensions/ublocklite/rulesets/scripting/declarative/easylist.js +3 -3
  179. package/extensions/ublocklite/rulesets/scripting/declarative/fin-0.js +3 -3
  180. package/extensions/ublocklite/rulesets/scripting/declarative/fra-0.js +3 -3
  181. package/extensions/ublocklite/rulesets/scripting/declarative/idn-0.js +3 -3
  182. package/extensions/ublocklite/rulesets/scripting/declarative/jpn-1.js +3 -3
  183. package/extensions/ublocklite/rulesets/scripting/declarative/kor-1.js +3 -3
  184. package/extensions/ublocklite/rulesets/scripting/declarative/rus-0.js +3 -3
  185. package/extensions/ublocklite/rulesets/scripting/declarative/spa-1.js +3 -3
  186. package/extensions/ublocklite/rulesets/scripting/declarative/swe-1.js +3 -3
  187. package/extensions/ublocklite/rulesets/scripting/declarative/tur-0.js +3 -3
  188. package/extensions/ublocklite/rulesets/scripting/declarative/ublock-filters.js +3 -3
  189. package/extensions/ublocklite/rulesets/scripting/declarative/ukr-0.js +3 -3
  190. package/extensions/ublocklite/rulesets/scripting/declarative/vie-1.js +1 -1
  191. package/extensions/ublocklite/rulesets/scripting/generic/annoyances-cookies.js +3 -3
  192. package/extensions/ublocklite/rulesets/scripting/generic/annoyances-social.js +3 -3
  193. package/extensions/ublocklite/rulesets/scripting/generic/chn-0.js +3 -3
  194. package/extensions/ublocklite/rulesets/scripting/generic/easylist.js +3 -3
  195. package/extensions/ublocklite/rulesets/scripting/generic/fin-0.js +2 -2
  196. package/extensions/ublocklite/rulesets/scripting/generic/fra-0.js +2 -2
  197. package/extensions/ublocklite/rulesets/scripting/generic/hrv-0.js +1 -1
  198. package/extensions/ublocklite/rulesets/scripting/generic/idn-0.js +2 -2
  199. package/extensions/ublocklite/rulesets/scripting/generic/ind-0.js +2 -2
  200. package/extensions/ublocklite/rulesets/scripting/generic/jpn-1.js +3 -3
  201. package/extensions/ublocklite/rulesets/scripting/generic/nor-0.js +1 -1
  202. package/extensions/ublocklite/rulesets/scripting/generic/rus-0.js +2 -2
  203. package/extensions/ublocklite/rulesets/scripting/generic/spa-1.js +2 -2
  204. package/extensions/ublocklite/rulesets/scripting/generic/tur-0.js +2 -2
  205. package/extensions/ublocklite/rulesets/scripting/generic/ublock-filters.js +3 -3
  206. package/extensions/ublocklite/rulesets/scripting/generic/ukr-0.js +3 -3
  207. package/extensions/ublocklite/rulesets/scripting/generichigh/annoyances-cookies.css +0 -1
  208. package/extensions/ublocklite/rulesets/scripting/generichigh/annoyances-social.css +0 -1
  209. package/extensions/ublocklite/rulesets/scripting/generichigh/chn-0.css +0 -4
  210. package/extensions/ublocklite/rulesets/scripting/generichigh/cze-0.css +0 -1
  211. package/extensions/ublocklite/rulesets/scripting/generichigh/easylist.css +5 -9
  212. package/extensions/ublocklite/rulesets/scripting/generichigh/idn-0.css +11 -0
  213. package/extensions/ublocklite/rulesets/scripting/generichigh/kor-1.css +0 -2
  214. package/extensions/ublocklite/rulesets/scripting/procedural/adguard-mobile.js +3 -3
  215. package/extensions/ublocklite/rulesets/scripting/procedural/annoyances-cookies.js +1 -1
  216. package/extensions/ublocklite/rulesets/scripting/procedural/annoyances-overlays.js +3 -3
  217. package/extensions/ublocklite/rulesets/scripting/procedural/chn-0.js +2 -2
  218. package/extensions/ublocklite/rulesets/scripting/procedural/deu-0.js +3 -3
  219. package/extensions/ublocklite/rulesets/scripting/procedural/easylist.js +3 -3
  220. package/extensions/ublocklite/rulesets/scripting/procedural/fin-0.js +3 -3
  221. package/extensions/ublocklite/rulesets/scripting/procedural/fra-0.js +3 -3
  222. package/extensions/ublocklite/rulesets/scripting/procedural/jpn-1.js +3 -3
  223. package/extensions/ublocklite/rulesets/scripting/procedural/kor-1.js +3 -3
  224. package/extensions/ublocklite/rulesets/scripting/procedural/nor-0.js +3 -3
  225. package/extensions/ublocklite/rulesets/scripting/procedural/rou-1.js +3 -3
  226. package/extensions/ublocklite/rulesets/scripting/procedural/rus-0.js +3 -3
  227. package/extensions/ublocklite/rulesets/scripting/procedural/rus-1.js +1 -1
  228. package/extensions/ublocklite/rulesets/scripting/procedural/spa-0.js +3 -3
  229. package/extensions/ublocklite/rulesets/scripting/procedural/spa-1.js +3 -3
  230. package/extensions/ublocklite/rulesets/scripting/procedural/swe-1.js +3 -3
  231. package/extensions/ublocklite/rulesets/scripting/procedural/ublock-filters.js +3 -3
  232. package/extensions/ublocklite/rulesets/scripting/procedural/ukr-0.js +3 -3
  233. package/extensions/ublocklite/rulesets/scripting/scriptlet/adguard-mobile.abort-current-script.js +2 -2
  234. package/extensions/ublocklite/rulesets/scripting/scriptlet/adguard-mobile.set-cookie-reload.js +11 -2
  235. package/extensions/ublocklite/rulesets/scripting/scriptlet/adguard-mobile.set-cookie.js +10 -1
  236. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-cookies.set-cookie.js +12 -3
  237. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-cookies.set-local-storage-item.js +2 -2
  238. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-cookies.trusted-click-element.js +2 -2
  239. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-cookies.trusted-set-cookie-reload.js +10 -1
  240. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-cookies.trusted-set-cookie.js +12 -3
  241. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-cookies.trusted-set-local-storage-item.js +2 -2
  242. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-others.remove-cookie.js +17 -7
  243. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-others.set-cookie.js +10 -1
  244. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-overlays.abort-current-script.js +1 -1
  245. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-overlays.abort-on-property-read.js +1 -1
  246. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-overlays.addEventListener-defuser.js +2 -2
  247. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-overlays.remove-attr.js +2 -2
  248. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-overlays.remove-class.js +1 -1
  249. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-overlays.remove-cookie.js +17 -7
  250. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-overlays.remove-node-text.js +2 -2
  251. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-overlays.set-constant.js +1 -1
  252. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-overlays.set-cookie.js +12 -3
  253. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-overlays.set-local-storage-item.js +2 -2
  254. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-overlays.trusted-set-cookie.js +10 -1
  255. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-overlays.trusted-set-local-storage-item.js +2 -2
  256. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-social.set-cookie.js +10 -1
  257. package/extensions/ublocklite/rulesets/scripting/scriptlet/chn-0.abort-current-script.js +2 -2
  258. package/extensions/ublocklite/rulesets/scripting/scriptlet/chn-0.abort-on-property-read.js +2 -2
  259. package/extensions/ublocklite/rulesets/scripting/scriptlet/chn-0.evaldata-prune.js +1 -1
  260. package/extensions/ublocklite/rulesets/scripting/scriptlet/chn-0.json-prune.js +3 -3
  261. package/extensions/ublocklite/rulesets/scripting/scriptlet/chn-0.prevent-setTimeout.js +1 -1
  262. package/extensions/ublocklite/rulesets/scripting/scriptlet/chn-0.set-constant.js +1 -1
  263. package/extensions/ublocklite/rulesets/scripting/scriptlet/cze-0.json-prune-xhr-response.js +597 -0
  264. package/extensions/ublocklite/rulesets/scripting/scriptlet/cze-0.remove-cookie.js +17 -7
  265. package/extensions/ublocklite/rulesets/scripting/scriptlet/easyprivacy.set-cookie.js +10 -1
  266. package/extensions/ublocklite/rulesets/scripting/scriptlet/fin-0.set-cookie.js +10 -1
  267. package/extensions/ublocklite/rulesets/scripting/scriptlet/fra-0.abort-on-property-read.js +2 -2
  268. package/extensions/ublocklite/rulesets/scripting/scriptlet/fra-0.adjust-setTimeout.js +2 -2
  269. package/extensions/ublocklite/rulesets/scripting/scriptlet/fra-0.prevent-fetch.js +2 -2
  270. package/extensions/ublocklite/rulesets/scripting/scriptlet/fra-0.set-constant.js +1 -1
  271. package/extensions/ublocklite/rulesets/scripting/scriptlet/fra-0.set-cookie.js +10 -1
  272. package/extensions/ublocklite/rulesets/scripting/scriptlet/hun-0.prevent-fetch.js +2 -2
  273. package/extensions/ublocklite/rulesets/scripting/scriptlet/hun-0.remove-cookie.js +17 -7
  274. package/extensions/ublocklite/rulesets/scripting/scriptlet/hun-0.set-constant.js +1 -1
  275. package/extensions/ublocklite/rulesets/scripting/scriptlet/hun-0.set-cookie.js +10 -1
  276. package/extensions/ublocklite/rulesets/scripting/scriptlet/irn-0.remove-cookie.js +17 -7
  277. package/extensions/ublocklite/rulesets/scripting/scriptlet/jpn-1.abort-current-script.js +2 -2
  278. package/extensions/ublocklite/rulesets/scripting/scriptlet/jpn-1.addEventListener-defuser.js +1 -1
  279. package/extensions/ublocklite/rulesets/scripting/scriptlet/jpn-1.adjust-setTimeout.js +1 -1
  280. package/extensions/ublocklite/rulesets/scripting/scriptlet/jpn-1.prevent-fetch.js +1 -1
  281. package/extensions/ublocklite/rulesets/scripting/scriptlet/jpn-1.prevent-setTimeout.js +2 -2
  282. package/extensions/ublocklite/rulesets/scripting/scriptlet/jpn-1.prevent-window-open.js +1 -1
  283. package/extensions/ublocklite/rulesets/scripting/scriptlet/jpn-1.remove-node-text.js +1 -1
  284. package/extensions/ublocklite/rulesets/scripting/scriptlet/jpn-1.set-constant.js +2 -2
  285. package/extensions/ublocklite/rulesets/scripting/scriptlet/jpn-1.set-cookie-reload.js +10 -1
  286. package/extensions/ublocklite/rulesets/scripting/scriptlet/kor-1.prevent-setTimeout.js +2 -2
  287. package/extensions/ublocklite/rulesets/scripting/scriptlet/kor-1.set-constant.js +2 -2
  288. package/extensions/ublocklite/rulesets/scripting/scriptlet/kor-1.set-cookie.js +10 -1
  289. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.abort-on-stack-trace.js +1 -1
  290. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.addEventListener-defuser.js +1 -1
  291. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.href-sanitizer.js +1 -1
  292. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.prevent-setTimeout.js +1 -1
  293. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.prevent-xhr.js +1 -1
  294. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.remove-cookie.js +19 -9
  295. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.remove-node-text.js +1 -1
  296. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.set-constant.js +3 -3
  297. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.set-cookie-reload.js +11 -2
  298. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.set-cookie.js +10 -1
  299. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-1.remove-cookie.js +17 -7
  300. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.abort-current-script.js +2 -2
  301. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.abort-on-property-read.js +2 -2
  302. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.abort-on-stack-trace.js +1 -1
  303. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.addEventListener-defuser.js +2 -2
  304. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.adjust-setInterval.js +2 -2
  305. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.adjust-setTimeout.js +2 -2
  306. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.prevent-fetch.js +2 -2
  307. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.prevent-setTimeout.js +1 -1
  308. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.prevent-window-open.js +2 -2
  309. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.prevent-xhr.js +1 -1
  310. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.remove-attr.js +2 -2
  311. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.remove-class.js +2 -2
  312. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.set-constant.js +2 -2
  313. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.set-cookie-reload.js +10 -1
  314. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.set-cookie.js +12 -3
  315. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.set-local-storage-item.js +1 -1
  316. package/extensions/ublocklite/rulesets/scripting/scriptlet/swe-1.remove-cookie.js +17 -7
  317. package/extensions/ublocklite/rulesets/scripting/scriptlet/swe-1.set-cookie.js +10 -1
  318. package/extensions/ublocklite/rulesets/scripting/scriptlet/tur-0.abort-current-script.js +2 -2
  319. package/extensions/ublocklite/rulesets/scripting/scriptlet/tur-0.abort-on-property-read.js +2 -2
  320. package/extensions/ublocklite/rulesets/scripting/scriptlet/tur-0.addEventListener-defuser.js +1 -1
  321. package/extensions/ublocklite/rulesets/scripting/scriptlet/tur-0.adjust-setInterval.js +2 -2
  322. package/extensions/ublocklite/rulesets/scripting/scriptlet/tur-0.prevent-setTimeout.js +2 -2
  323. package/extensions/ublocklite/rulesets/scripting/scriptlet/tur-0.prevent-window-open.js +1 -1
  324. package/extensions/ublocklite/rulesets/scripting/scriptlet/tur-0.remove-attr.js +2 -2
  325. package/extensions/ublocklite/rulesets/scripting/scriptlet/tur-0.set-constant.js +2 -2
  326. package/extensions/ublocklite/rulesets/scripting/scriptlet/tur-0.set-cookie.js +10 -1
  327. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-badware.abort-current-script.js +2 -2
  328. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.abort-current-script.js +3 -3
  329. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.abort-on-property-read.js +2 -2
  330. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.abort-on-property-write.js +1 -1
  331. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.abort-on-stack-trace.js +2 -2
  332. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.addEventListener-defuser.js +3 -3
  333. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.adjust-setInterval.js +3 -3
  334. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.adjust-setTimeout.js +2 -2
  335. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.json-edit.js +30 -7
  336. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.json-prune-xhr-response.js +3 -3
  337. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.json-prune.js +3 -3
  338. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.jsonl-edit-xhr-response.js +19 -2
  339. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.noeval-if.js +3 -3
  340. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.prevent-fetch.js +1 -1
  341. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.prevent-refresh.js +1 -1
  342. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.prevent-setTimeout.js +2 -2
  343. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.prevent-window-open.js +2 -2
  344. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.prevent-xhr.js +3 -3
  345. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.remove-attr.js +2 -2
  346. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.remove-cookie.js +19 -9
  347. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.remove-node-text.js +3 -3
  348. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.set-constant.js +3 -3
  349. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.set-cookie.js +12 -3
  350. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.set-local-storage-item.js +2 -2
  351. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.trusted-replace-argument.js +2 -2
  352. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.trusted-replace-node-text.js +3 -3
  353. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.trusted-replace-outbound-text.js +2 -2
  354. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.trusted-set-constant.js +2 -2
  355. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.trusted-set-cookie-reload.js +10 -1
  356. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.trusted-set-cookie.js +13 -4
  357. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.trusted-set-local-storage-item.js +399 -0
  358. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.trusted-suppress-native-method.js +2 -2
  359. package/extensions/ublocklite/rulesets/scripting/scriptlet/ubol-tests.jsonl-edit-fetch-response.js +19 -2
  360. package/extensions/ublocklite/rulesets/scripting/scriptlet/ubol-tests.jsonl-edit-xhr-response.js +19 -2
  361. package/extensions/ublocklite/rulesets/scripting/scriptlet/ukr-0.abort-current-script.js +2 -2
  362. package/extensions/ublocklite/rulesets/scripting/scriptlet/ukr-0.abort-on-property-read.js +1 -1
  363. package/extensions/ublocklite/rulesets/scripting/scriptlet/ukr-0.abort-on-property-write.js +1 -1
  364. package/extensions/ublocklite/rulesets/scripting/scriptlet/ukr-0.remove-class.js +1 -1
  365. package/extensions/ublocklite/rulesets/scripting/scriptlet/ukr-0.set-constant.js +2 -2
  366. package/extensions/ublocklite/rulesets/scripting/scriptlet/vie-1.abort-current-script.js +1 -1
  367. package/extensions/ublocklite/rulesets/scripting/scriptlet/vie-1.abort-on-property-read.js +2 -2
  368. package/extensions/ublocklite/rulesets/scripting/scriptlet/vie-1.set-constant.js +2 -2
  369. package/extensions/ublocklite/rulesets/scripting/specific/adguard-mobile.js +3 -3
  370. package/extensions/ublocklite/rulesets/scripting/specific/annoyances-cookies.js +3 -3
  371. package/extensions/ublocklite/rulesets/scripting/specific/annoyances-others.js +3 -3
  372. package/extensions/ublocklite/rulesets/scripting/specific/annoyances-overlays.js +3 -3
  373. package/extensions/ublocklite/rulesets/scripting/specific/annoyances-social.js +3 -3
  374. package/extensions/ublocklite/rulesets/scripting/specific/chn-0.js +3 -3
  375. package/extensions/ublocklite/rulesets/scripting/specific/deu-0.js +3 -3
  376. package/extensions/ublocklite/rulesets/scripting/specific/easylist.js +3 -3
  377. package/extensions/ublocklite/rulesets/scripting/specific/fin-0.js +3 -3
  378. package/extensions/ublocklite/rulesets/scripting/specific/fra-0.js +3 -3
  379. package/extensions/ublocklite/rulesets/scripting/specific/grc-0.js +3 -3
  380. package/extensions/ublocklite/rulesets/scripting/specific/hun-0.js +3 -3
  381. package/extensions/ublocklite/rulesets/scripting/specific/idn-0.js +3 -3
  382. package/extensions/ublocklite/rulesets/scripting/specific/ind-0.js +3 -3
  383. package/extensions/ublocklite/rulesets/scripting/specific/isr-0.js +1 -1
  384. package/extensions/ublocklite/rulesets/scripting/specific/ita-0.js +3 -3
  385. package/extensions/ublocklite/rulesets/scripting/specific/jpn-1.js +3 -3
  386. package/extensions/ublocklite/rulesets/scripting/specific/kor-1.js +3 -3
  387. package/extensions/ublocklite/rulesets/scripting/specific/ltu-0.js +3 -3
  388. package/extensions/ublocklite/rulesets/scripting/specific/nld-0.js +3 -3
  389. package/extensions/ublocklite/rulesets/scripting/specific/nor-0.js +3 -3
  390. package/extensions/ublocklite/rulesets/scripting/specific/rou-1.js +3 -3
  391. package/extensions/ublocklite/rulesets/scripting/specific/rus-0.js +3 -3
  392. package/extensions/ublocklite/rulesets/scripting/specific/spa-0.js +3 -3
  393. package/extensions/ublocklite/rulesets/scripting/specific/spa-1.js +3 -3
  394. package/extensions/ublocklite/rulesets/scripting/specific/swe-1.js +3 -3
  395. package/extensions/ublocklite/rulesets/scripting/specific/tur-0.js +3 -3
  396. package/extensions/ublocklite/rulesets/scripting/specific/ublock-badware.js +3 -3
  397. package/extensions/ublocklite/rulesets/scripting/specific/ublock-filters.js +3 -3
  398. package/extensions/ublocklite/rulesets/scripting/specific/ukr-0.js +3 -3
  399. package/extensions/ublocklite/rulesets/scripting/specific/vie-1.js +3 -3
  400. package/extensions/ublocklite/rulesets/scriptlet-details.json +157 -153
  401. package/extensions/ublocklite/rulesets/strictblock/adguard-mobile.json +1 -34
  402. package/extensions/ublocklite/rulesets/strictblock/chn-0.json +198 -248
  403. package/extensions/ublocklite/rulesets/strictblock/dpollock-0.json +2 -0
  404. package/extensions/ublocklite/rulesets/strictblock/easylist.json +3 -2
  405. package/extensions/ublocklite/rulesets/strictblock/easyprivacy.json +37 -1
  406. package/extensions/ublocklite/rulesets/strictblock/fra-0.json +304 -62
  407. package/extensions/ublocklite/rulesets/strictblock/grc-0.json +1 -7
  408. package/extensions/ublocklite/rulesets/strictblock/idn-0.json +1 -0
  409. package/extensions/ublocklite/rulesets/strictblock/ita-0.json +1 -0
  410. package/extensions/ublocklite/rulesets/strictblock/jpn-1.json +159 -155
  411. package/extensions/ublocklite/rulesets/strictblock/kor-1.json +1 -0
  412. package/extensions/ublocklite/rulesets/strictblock/nor-0.json +1 -1
  413. package/extensions/ublocklite/rulesets/strictblock/pgl.json +10 -7
  414. package/extensions/ublocklite/rulesets/strictblock/spa-1.json +0 -11
  415. package/extensions/ublocklite/rulesets/strictblock/stevenblack-hosts.json +7223 -999
  416. package/extensions/ublocklite/rulesets/strictblock/tur-0.json +0 -13
  417. package/extensions/ublocklite/rulesets/strictblock/ublock-badware.json +569 -570
  418. package/extensions/ublocklite/rulesets/strictblock/ublock-filters.json +1 -1
  419. package/extensions/ublocklite/rulesets/strictblock/ukr-0.json +0 -75
  420. package/extensions/ublocklite/rulesets/strictblock/urlhaus-full.json +339 -766
  421. package/extensions/ublocklite/rulesets/strictblock/vie-1.json +3 -2
  422. package/extensions/ublocklite/rulesets/urlskip/ublock-filters.json +13 -0
  423. package/extensions/ublocklite/ublock.zip +0 -0
  424. package/package.json +24 -19
  425. package/src/routes/management/tests/management.spec.ts +25 -0
  426. package/src/server.ts +4 -5
  427. package/src/shared/utils/enjoi-resolver.ts +565 -0
  428. package/static/docs/swagger.json +9 -9
  429. package/static/docs/swagger.min.json +9 -9
  430. package/static/function/client.js +86 -39
  431. package/static/function/index.html +86 -39
  432. /package/extensions/ublocklite/lib/codemirror/{LICENSE → codemirror-quickstart.LICENSE} +0 -0
@@ -19,871 +19,606 @@
19
19
  Home: https://github.com/gorhill/uBlock
20
20
  */
21
21
 
22
- import {
23
- browser,
24
- localRead,
25
- localRemove,
26
- localWrite,
27
- sendMessage,
28
- } from './ext.js';
29
- import { dom, qs$ } from './dom.js';
30
- import { rulesFromText, textFromRules } from './dnr-parser.js';
31
- import { dnr } from './ext-compat.js';
32
- import { i18n$ } from './i18n.js';
22
+ import { dom, qs$, qsa$ } from './dom.js';
23
+ import { localRead, localWrite, sendMessage } from './ext.js';
24
+ import { ModeEditor } from './mode-editor.js';
25
+ import { ReadOnlyDNREditor } from './ro-dnr-editor.js';
26
+ import { ReadWriteDNREditor } from './rw-dnr-editor.js';
27
+ import { faIconsInit } from './fa-icons.js';
28
+ import { i18n } from './i18n.js';
33
29
 
34
30
  /******************************************************************************/
35
31
 
36
- // Details of YAML document(s) intersecting with a text span. If the text span
37
- // starts on a YAML document divider, the previous YAML document will be
38
- // included. If the text span ends on a YAML document divider, the next YAML
39
- // document will be included.
32
+ class Editor {
33
+ constructor() {
34
+ this.lastSavedText = '';
35
+ this.view = null;
36
+ this.reYamlDocSeparator = /^(?:---|...)\s*$/;
37
+ this.modifiedRange = { start: 0, end: 0 };
38
+ this.updateTimer = undefined;
39
+ this.ioPanel = self.cm6.createViewPanel();
40
+ this.summaryPanel = self.cm6.createViewPanel();
41
+ this.panels = [];
42
+ }
40
43
 
41
- function snapToYamlDocument(doc, start, end) {
42
- let yamlDocStart = doc.lineAt(start).number;
43
- if ( reYamlDocSeparator.test(doc.line(yamlDocStart).text) ) {
44
- if ( yamlDocStart > 1 ) {
45
- yamlDocStart -= 1;
44
+ async init() {
45
+ this.editors = {
46
+ 'modes': new ModeEditor(this),
47
+ 'dnr.rw': new ReadWriteDNREditor(this),
48
+ 'dnr.ro': new ReadOnlyDNREditor(this),
49
+ };
50
+ const rulesetDetails = await sendMessage({ what: 'getRulesetDetails' });
51
+ const parent = qs$('#editors optgroup');
52
+ for ( const details of rulesetDetails ) {
53
+ const option = document.createElement('option');
54
+ option.value = `dnr.ro.${details.id}`;
55
+ option.textContent = details.name;
56
+ parent.append(option);
46
57
  }
58
+ this.validModes = Array.from(qsa$('#editors option')).map(a => a.value);
59
+ const mode = await localRead('dashboard.develop.editor');
60
+ this.editorFromMode(mode);
61
+ const text = this.normalizeEditorText(await this.editor.getText(this.mode));
62
+ const viewConfig = {
63
+ text,
64
+ yamlLike: true,
65
+ oneDark: dom.cl.has(':root', 'dark'),
66
+ updateListener: info => { this.viewUpdateListener(info); },
67
+ saveListener: ( ) => { this.saveEditorText(); },
68
+ lineError: true,
69
+ spanError: true,
70
+ // https://codemirror.net/examples/autocompletion/
71
+ autocompletion: {
72
+ override: [
73
+ context => {
74
+ return this.autoComplete(context);
75
+ },
76
+ ],
77
+ activateOnCompletion: ( ) => true,
78
+ },
79
+ gutterClick: (view, info) => {
80
+ return this.gutterClick(view, info);
81
+ },
82
+ hoverTooltip: (view, pos, side) => {
83
+ return this.hoverTooltip(view, pos, side);
84
+ },
85
+ streamParser: this.streamParser,
86
+ foldService: (state, from) => {
87
+ return this.foldService(state, from);
88
+ },
89
+ readOnly: this.isReadOnly(),
90
+ };
91
+ viewConfig.panels = [ this.ioPanel, this.summaryPanel, ...this.panels ];
92
+ this.view = self.cm6.createEditorView(viewConfig, qs$('#cm-container'));
93
+ this.lastSavedText = text;
94
+ self.cm6.foldAll(this.view);
95
+ self.cm6.resetUndoRedo(this.view);
96
+ this.updateIOPanel();
97
+ this.editor.on?.(this);
98
+ this.modifiedRange.start = 1;
99
+ this.modifiedRange.end = this.view.state.doc.lines;
100
+ this.updateViewAsync();
47
101
  }
48
- while ( yamlDocStart > 1 ) {
49
- const line = doc.line(yamlDocStart);
50
- if ( reYamlDocSeparator.test(line.text) ) { break; }
51
- yamlDocStart -= 1;
102
+
103
+ normalizeEditorText(text) {
104
+ text ||= '';
105
+ text = text.trim();
106
+ if ( text !== '' ) { text += '\n'; }
107
+ return text;
52
108
  }
53
- const lastLine = doc.lines;
54
- let yamlDocEnd = doc.lineAt(end).number;
55
- if ( reYamlDocSeparator.test(doc.line(yamlDocEnd).text) ) {
56
- if ( yamlDocEnd < lastLine ) {
57
- yamlDocEnd += 1;
109
+
110
+ setEditorText(text, saved = false) {
111
+ text = this.normalizeEditorText(text);
112
+ if ( saved ) {
113
+ this.lastSavedText = text;
58
114
  }
115
+ this.view.dispatch({
116
+ changes: {
117
+ from: 0, to: this.view.state.doc.length,
118
+ insert: text,
119
+ },
120
+ });
121
+ this.view.focus();
59
122
  }
60
- while ( yamlDocEnd < lastLine ) {
61
- const line = doc.line(yamlDocEnd);
62
- if ( reYamlDocSeparator.test(line.text) ) { break; }
63
- yamlDocEnd += 1;
64
- }
65
- return { yamlDocStart, yamlDocEnd };
66
- }
67
-
68
- function rangeFromTransaction(transaction) {
69
- let from, to;
70
- transaction.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
71
- if ( from === undefined || fromB < from ) { from = fromB; }
72
- if ( to === undefined || toB > to ) { to = toB; }
73
- });
74
- return { from, to };
75
- }
76
123
 
77
- function addToModifiedRange(transaction) {
78
- const { from, to } = rangeFromTransaction(transaction);
79
- if ( from === undefined || to === undefined ) { return; }
80
- const { newDoc } = transaction;
81
- const { yamlDocStart, yamlDocEnd } = snapToYamlDocument(newDoc, from, to);
82
- if ( modifiedRange.start === -1 || yamlDocStart < modifiedRange.start ) {
83
- modifiedRange.start = yamlDocStart;
84
- }
85
- if ( modifiedRange.end === -1 || yamlDocEnd > modifiedRange.end ) {
86
- modifiedRange.end = yamlDocEnd;
124
+ getEditorText() {
125
+ return this.view.state.doc.toString();
87
126
  }
88
- }
89
-
90
- const reYamlDocSeparator = /^(?:---|...)\s*$/;
91
- const modifiedRange = { start: -1, end: -1 };
92
-
93
- /******************************************************************************/
94
127
 
95
- function rulesFromJSON(json) {
96
- let content = json.trim();
97
- if ( /^[[{]/.test(content) === false ) {
98
- const match = /^[^[{]+/.exec(content);
99
- if ( match === null ) { return; }
100
- content = content.slice(match[0].length);
101
- }
102
- const firstChar = content.charAt(0);
103
- const expectedLastChar = firstChar === '[' ? ']' : '}';
104
- if ( content.at(-1) !== expectedLastChar ) {
105
- const re = new RegExp(`\\${expectedLastChar}[^\\${expectedLastChar}]+$`);
106
- const match = re.exec(content);
107
- if ( match === null ) { return; }
108
- content = content.slice(0, match.index+1);
109
- }
110
- if ( content.startsWith('{') && content.endsWith('}') ) {
111
- content = `[${content}]`;
112
- }
113
- try {
114
- const rules = JSON.parse(content);
115
- if ( Array.isArray(rules) ) { return rules; }
128
+ editorTextChanged() {
129
+ const text = this.normalizeEditorText(this.getEditorText());
130
+ return text !== this.lastSavedText;
116
131
  }
117
- catch {
118
- }
119
- }
120
-
121
- /******************************************************************************/
122
132
 
123
- function lineIndentAt(line) {
124
- const match = /^(?: {2})*/.exec(line.text);
125
- const indent = match !== null ? match[0].length : -1;
126
- if ( indent === -1 || (indent & 1) !== 0 ) { return -1; }
127
- return indent / 2;
128
- }
133
+ async selectEditor(mode) {
134
+ if ( mode === this.mode ) { return; }
135
+ this.editorFromMode(mode);
136
+ const text = await this.editor.getText(this.mode);
137
+ this.setEditorText(text);
138
+ this.lastSavedText = this.getEditorText();
139
+ self.cm6.foldAll(this.view)
140
+ self.cm6.resetUndoRedo(this.view);
141
+ self.cm6.toggleReadOnly(this.view, this.isReadOnly());
142
+ this.updateIOPanel();
143
+ this.editor.on?.(this);
144
+ this.modifiedRange.start = 1;
145
+ this.modifiedRange.end = this.view.state.doc.lines;
146
+ this.updateViewAsync();
147
+ }
129
148
 
130
- function getScopeAt(from) {
131
- const { doc } = cmRules.state;
132
- const lineFrom = doc.lineAt(from);
133
- let depth = lineIndentAt(lineFrom);
134
- if ( depth === -1 ) { return; }
135
- const text = lineFrom.text.trim();
136
- if ( text.startsWith('#') ) { return; }
137
- const path = [];
138
- const pos = text.indexOf(':');
139
- if ( pos !== -1 ) {
140
- path.push(text.slice(0, pos+1));
141
- }
142
- let lineNo = lineFrom.number;
143
- while ( depth > 0 && lineNo > 1 ) {
144
- lineNo -= 1;
145
- const lineBefore = doc.line(lineNo);
146
- const text = lineBefore.text.trim();
147
- if ( text.startsWith('#') ) { continue; }
148
- if ( lineIndentAt(lineBefore) > (depth-1) ) { continue; }
149
- const match = /^- ([^:]+:)/.exec(text);
150
- if ( match !== null ) {
151
- path.unshift(match[1]);
149
+ editorFromMode(mode) {
150
+ if ( this.validModes.includes(mode) === false ) {
151
+ mode = 'modes';
152
+ }
153
+ if ( mode === this.mode ) { return mode; }
154
+ let editor;
155
+ if ( mode === 'modes' ) {
156
+ editor = this.editors['modes'];
157
+ } else if ( mode.startsWith('dnr.rw.') ) {
158
+ editor = this.editors['dnr.rw'];
159
+ } else if ( mode.startsWith('dnr.ro.') ) {
160
+ editor = this.editors['dnr.ro'];
152
161
  } else {
153
- path.unshift(text);
162
+ return;
154
163
  }
155
- depth -= 1;
164
+ this.editor?.off?.(this);
165
+ this.editor = editor;
166
+ this.mode = mode;
167
+ const select = qs$('#editors');
168
+ select.value = mode;
156
169
  }
157
- return path.join('');
158
- }
159
170
 
160
- function getAutocompleteCandidates(from) {
161
- const scope = getScopeAt(from);
162
- switch ( scope ) {
163
- case '':
164
- return {
165
- before: /^$/,
166
- candidates: [
167
- { token: 'action:', after: '\n ' },
168
- { token: 'condition:', after: '\n ' },
169
- { token: 'priority:', after: ' ' },
170
- { token: '---', after: '\n' },
171
- ]
172
- };
173
- case 'action:':
174
- return {
175
- before: /^ {2}$/,
176
- candidates: [
177
- { token: 'type:', after: ' ' },
178
- { token: 'redirect:', after: '\n ' },
179
- { token: 'requestHeaders:', after: '\n - header: ' },
180
- { token: 'responseHeaders:', after: '\n - header: ' },
181
- ],
182
- };
183
- case 'action:type:':
184
- return {
185
- before: /: $/,
186
- candidates: [
187
- { token: 'block', after: '\n ' },
188
- { token: 'redirect', after: '\n ' },
189
- { token: 'allow', after: '\n ' },
190
- { token: 'modifyHeaders', after: '\n ' },
191
- { token: 'upgradeScheme', after: '\n ' },
192
- { token: 'allowAllRequest', after: '\n ' },
193
- ],
194
- };
195
- case 'action:redirect:':
196
- return {
197
- before: /^ {4}$/,
198
- candidates: [
199
- { token: 'extensionPath:', after: ' ' },
200
- { token: 'regexSubstitution:', after: ' ' },
201
- { token: 'transform:', after: '\n ' },
202
- { token: 'url:', after: ' ' },
203
- ],
204
- };
205
- case 'action:redirect:transform:':
206
- return {
207
- before: /^ {6}$/,
208
- candidates: [
209
- { token: 'fragment:', after: ' ' },
210
- { token: 'host:', after: ' ' },
211
- { token: 'path:', after: ' ' },
212
- { token: 'port:', after: ' ' },
213
- { token: 'query:', after: ' ' },
214
- { token: 'scheme:', after: ' ' },
215
- { token: 'queryTransform:', after: '\n ' },
216
- ],
217
- };
218
- case 'action:redirect:transform:queryTransform:':
219
- return {
220
- before: /^ {8}$/,
221
- candidates: [
222
- { token: 'addOrReplaceParams:', after: '\n - ' },
223
- { token: 'removeParams:', after: '\n - ' },
224
- ],
225
- };
226
- case 'action:responseHeaders:':
227
- case 'action:requestHeaders:':
228
- return {
229
- before: /^ {4}- $/,
230
- candidates: [
231
- { token: 'header:', after: ' ' },
232
- ],
233
- };
234
- case 'action:responseHeaders:header:':
235
- case 'action:requestHeaders:header:':
236
- return {
237
- before: /^ {6}$/,
238
- candidates: [
239
- { token: 'operation:', after: ' ' },
240
- { token: 'value:', after: ' ' },
241
- ],
242
- };
243
- case 'action:responseHeaders:header:operation:':
244
- case 'action:requestHeaders:header:operation:':
245
- return {
246
- before: /: $/,
247
- candidates: [
248
- { token: 'append', after: '\n value: ' },
249
- { token: 'set', after: '\n value: ' },
250
- { token: 'remove', after: '\n ' },
251
- ],
252
- };
253
- case 'condition:':
254
- return {
255
- before: /^ {2}$/,
256
- candidates: [
257
- { token: 'domainType:', after: ' ' },
258
- { token: 'isUrlFilterCaseSensitive:', after: ' ' },
259
- { token: 'regexFilter:', after: ' ' },
260
- { token: 'urlFilter:', after: ' ' },
261
- { token: 'initiatorDomains:', after: '\n - ' },
262
- { token: 'excludedInitiatorDomains:', after: '\n - ' },
263
- { token: 'requestDomains:', after: '\n - ' },
264
- { token: 'excludedRequestDomains:', after: '\n - ' },
265
- { token: 'resourceTypes:', after: '\n - ' },
266
- { token: 'excludedResourceTypes:', after: '\n - ' },
267
- { token: 'requestMethods:', after: '\n - ' },
268
- { token: 'excludedRequestMethods:', after: '\n - ' },
269
- { token: 'responseHeaders:', after: '\n - ' },
270
- { token: 'excludedResponseHeaders:', after: '\n - ' },
271
- ],
272
- };
273
- case 'condition:domainType:':
274
- return {
275
- before: /: $/,
276
- candidates: [
277
- { token: 'firstParty', after: '\n ' },
278
- { token: 'thirdParty', after: '\n ' },
279
- ],
280
- };
281
- case 'condition:isUrlFilterCaseSensitive:':
282
- return {
283
- before: /: $/,
284
- candidates: [
285
- { token: 'true', after: '\n ' },
286
- { token: 'false', after: '\n ' },
287
- ],
288
- };
289
- case 'condition:requestMethods:':
290
- case 'condition:excludedRequestMethods:':
291
- return {
292
- before: /^ {4}- $/,
293
- candidates: [
294
- { token: 'connect', after: '\n - ' },
295
- { token: 'delete', after: '\n - ' },
296
- { token: 'get', after: '\n - ' },
297
- { token: 'head', after: '\n - ' },
298
- { token: 'options', after: '\n - ' },
299
- { token: 'patch', after: '\n - ' },
300
- { token: 'post', after: '\n - ' },
301
- { token: 'put', after: '\n - ' },
302
- { token: 'other', after: '\n ' },
303
- ],
304
- };
305
- case 'condition:resourceTypes:':
306
- case 'condition:excludedResourceTypes:':
307
- return {
308
- before: /^ {4}- $/,
309
- candidates: [
310
- { token: 'main_frame', after: '\n - ' },
311
- { token: 'sub_frame', after: '\n - ' },
312
- { token: 'stylesheet', after: '\n - ' },
313
- { token: 'script', after: '\n - ' },
314
- { token: 'image', after: '\n - ' },
315
- { token: 'font', after: '\n - ' },
316
- { token: 'object', after: '\n - ' },
317
- { token: 'xmlhttprequest', after: '\n - ' },
318
- { token: 'ping', after: '\n - ' },
319
- { token: 'csp_report', after: '\n - ' },
320
- { token: 'media', after: '\n - ' },
321
- { token: 'websocket', after: '\n - ' },
322
- { token: 'webtransport', after: '\n - ' },
323
- { token: 'webbundle', after: '\n - ' },
324
- { token: 'other', after: '\n ' },
325
- ],
326
- };
171
+ isReadOnly() {
172
+ return typeof this.editor.saveEditorText !== 'function';
327
173
  }
328
- }
329
174
 
330
- function autoComplete(context) {
331
- const match = context.matchBefore(/[\w-]*/);
332
- if ( match === undefined ) { return null; }
333
- const result = getAutocompleteCandidates(match.from);
334
- if ( result === undefined ) { return null; }
335
- if ( result.before !== undefined ) {
336
- const { doc } = context.state;
337
- const line = doc.lineAt(context.pos);
338
- const before = doc.sliceString(line.from, match.from);
339
- if ( result.before.test(before) === false ) { return null; }
340
- }
341
- const filtered = result.candidates.filter(e =>
342
- e.token !== match.text || e.after !== '\n'
343
- );
344
- return {
345
- from: match.from,
346
- options: filtered.map(e => ({ label: e.token, apply: `${e.token}${e.after}` })),
347
- validFor: /\w*/,
348
- };
349
- }
350
-
351
- /******************************************************************************/
352
-
353
- function setEditorText(text) {
354
- if ( text === undefined ) { return; }
355
- if ( text !== '' ) { text += '\n'; }
356
- cmRules.dispatch({
357
- changes: {
358
- from: 0, to: cmRules.state.doc.length,
359
- insert: text,
360
- },
361
- });
362
- cmRules.focus();
363
- }
364
-
365
- function getEditorText() {
366
- return cmRules.state.doc.toString();
367
- }
368
-
369
- /******************************************************************************/
370
-
371
- function saveEditorText() {
372
- const text = getEditorText().trim();
373
- const promise = text.length !== 0
374
- ? localWrite('userDnrRules', text)
375
- : localRemove('userDnrRules');
376
- promise.then(( ) => {
377
- lastSavedText = text;
378
- updateView();
379
- }).then(( ) =>
380
- sendMessage({ what: 'updateUserDnrRules' })
381
- ).then(result => {
382
- if ( result instanceof Object === false ) { return; }
383
- updateFeedbackPanel(result);
384
- });
385
- }
386
-
387
- /******************************************************************************/
388
-
389
- async function validateRegexes(regexes) {
390
- if ( regexes.length === 0 ) { return; }
391
- const promises = regexes.map(regex => validateRegex(regex));
392
- await Promise.all(promises);
393
- for ( const regex of regexes ) {
394
- const i = validatedRegexes.regexes.indexOf(regex);
395
- if ( i === -1 ) { continue; }
396
- const reason = validatedRegexes.results[i];
397
- if ( reason === true ) { continue; }
398
- const entries = self.cm6.findAll(cmRules,
399
- `(?<=\\bregexFilter: )${RegExp.escape(regex)}`
400
- );
401
- for ( const entry of entries ) {
402
- self.cm6.spanErrorAdd(cmRules, entry.from, entry.to, reason);
175
+ viewUpdateListener(info) {
176
+ if ( info.docChanged === false ) { return; }
177
+ for ( const transaction of info.transactions ) {
178
+ if ( transaction.docChanged === false ) { continue; }
179
+ this.addToModifiedRange(transaction);
180
+ if ( transaction.isUserEvent('delete.backward') ) {
181
+ this.smartBackspace(transaction);
182
+ } else if ( transaction.isUserEvent('input.paste') ) {
183
+ if ( this.editor.importFromPaste ) {
184
+ this.editor.importFromPaste(this, transaction);
185
+ }
186
+ } else if ( transaction.isUserEvent('input') ) {
187
+ if ( this.smartReturn(transaction) ) { continue; }
188
+ this.smartSpacebar(transaction);
189
+ }
403
190
  }
191
+ this.updateViewAsync();
404
192
  }
405
- }
406
193
 
407
- async function validateRegex(regex) {
408
- const details = await dnr.isRegexSupported({ regex });
409
- const result = details.isSupported || details.reason;
410
- if ( validatedRegexes.regexes.length > 32 ) {
411
- validatedRegexes.regexes.pop();
412
- validatedRegexes.results.pop();
194
+ updateViewAsync() {
195
+ if ( this.updateTimer !== undefined ) { return; }
196
+ this.updateTimer = self.setTimeout(( ) => {
197
+ this.updateTimer = undefined;
198
+ this.updateView();
199
+ }, 71);
413
200
  }
414
- validatedRegexes.regexes.unshift(regex);
415
- validatedRegexes.results.unshift(result);
416
- }
417
201
 
418
- const validatedRegexes = {
419
- regexes: [],
420
- results: [],
421
- };
422
-
423
- /******************************************************************************/
202
+ updateView() {
203
+ const { doc } = this.view.state;
204
+ const changed = this.editorTextChanged();
205
+ dom.attr('#apply', 'disabled', changed ? null : '');
206
+ dom.attr('#revert', 'disabled', changed ? null : '');
207
+ if ( typeof this.editor.updateView !== 'function' ) { return; }
208
+ let { start, end } = this.modifiedRange;
209
+ if ( start === 0 || end === 0 ) { return; }
210
+ this.modifiedRange.start = this.modifiedRange.end = 0;
211
+ if ( start > doc.lines ) { start = doc.lines; }
212
+ if ( end > doc.lines ) { end = doc.lines; }
213
+ self.cm6.lineErrorClear(this.view, start, end);
214
+ self.cm6.spanErrorClear(this.view, start, end);
215
+ const firstLine = doc.line(start);
216
+ const lastLine = doc.line(end);
217
+ this.editor.updateView(this, firstLine, lastLine);
218
+ }
424
219
 
425
- function updateView() {
426
- const { doc } = cmRules.state;
427
- const changed = doc.toString().trim() !==
428
- lastSavedText.trim();
429
- dom.attr('#dnrRulesApply', 'disabled', changed ? null : '');
430
- dom.attr('#dnrRulesRevert', 'disabled', changed ? null : '');
431
- const { start, end } = modifiedRange;
432
- if ( start === -1 || end === -1 ) { return; }
433
- modifiedRange.start = modifiedRange.end = -1;
434
- self.cm6.lineErrorClear(cmRules, start, end);
435
- self.cm6.spanErrorClear(cmRules, start, end);
436
- const firstLine = doc.line(start);
437
- const lastLine = doc.line(end);
438
- const text = doc.sliceString(firstLine.from, lastLine.to);
439
- const { bad } = rulesFromText(text);
440
- if ( Array.isArray(bad) && bad.length !== 0 ) {
441
- self.cm6.lineErrorAdd(cmRules, bad.map(i => i + start));
442
- }
443
- const entries = self.cm6.findAll(
444
- cmRules,
445
- '\\bregexFilter: (\\S+)',
446
- firstLine.from,
447
- lastLine.to
448
- );
449
- const regexes = [];
450
- for ( const entry of entries ) {
451
- const regex = entry.match[1];
452
- const i = validatedRegexes.regexes.indexOf(regex);
453
- if ( i !== -1 ) {
454
- const reason = validatedRegexes.results[i];
455
- if ( reason === true ) { continue; }
456
- self.cm6.spanErrorAdd(cmRules, entry.from+13, entry.to, reason);
457
- } else {
458
- regexes.push(regex);
220
+ updateIOPanel() {
221
+ const ioButtons = [];
222
+ if ( this.editor.saveEditorText ) {
223
+ ioButtons.push('apply', 'revert');
224
+ }
225
+ if ( this.editor.importFromFile ) {
226
+ ioButtons.push('import');
459
227
  }
228
+ if ( this.editor.exportToFile ) {
229
+ ioButtons.push('export');
230
+ }
231
+ if ( ioButtons.length === 0 ) {
232
+ return this.ioPanel.render(this.view, null);
233
+ }
234
+ const template = document.querySelector('template.io-panel');
235
+ const fragment = template.content.cloneNode(true);
236
+ const root = fragment.querySelector('.io-panel');
237
+ i18n.render(root);
238
+ faIconsInit(root);
239
+ root.dataset.io = ioButtons.join(' ');
240
+ const config = {
241
+ dom: root,
242
+ mount: ( ) => {
243
+ dom.on('#apply', 'click', ( ) => {
244
+ this.saveEditorText();
245
+ });
246
+ dom.on('#revert', 'click', ( ) => {
247
+ this.revertEditorText();
248
+ });
249
+ dom.on('#import', 'click', ( ) => {
250
+ this.importFromFile()
251
+ });
252
+ dom.on('#export', 'click', ( ) => {
253
+ this.exportToFile();
254
+ });
255
+ }
256
+ };
257
+ this.ioPanel.render(this.view, config);
460
258
  }
461
- validateRegexes(regexes);
462
- }
463
259
 
464
- function updateViewAsync() {
465
- if ( updateViewAsync.timer !== undefined ) { return; }
466
- updateViewAsync.timer = self.setTimeout(( ) => {
467
- updateViewAsync.timer = undefined;
468
- updateView();
469
- }, 71);
470
- }
260
+ updateSummaryPanel(dom) {
261
+ if ( dom instanceof Object ) {
262
+ if ( this.updateSummaryPanel.timer !== undefined ) {
263
+ self.clearTimeout(this.updateSummaryPanel.timer);
264
+ this.updateSummaryPanel.timer = undefined;
265
+ }
266
+ return this.summaryPanel.render(this.view, { dom });
267
+ }
268
+ if ( this.updateSummaryPanel.timer !== undefined ) { return; }
269
+ this.updateSummaryPanel.timer = self.setTimeout(( ) => {
270
+ this.updateSummaryPanel.timer = undefined;
271
+ this.summaryPanel.render(this.view, null);
272
+ }, 157);
273
+ }
471
274
 
472
- /******************************************************************************/
275
+ autoComplete(context) {
276
+ if ( typeof this.editor.autoComplete !== 'function' ) { return null; }
277
+ return this.editor.autoComplete(this, context);
278
+ }
473
279
 
474
- function updateSummaryPanel(info) {
475
- self.cm6.showSummaryPanel(cmRules, {
476
- template: '.summary-panel',
477
- text: i18n$('dnrRulesCountInfo')
478
- .replace('{count}', (info.userDnrRuleCount || 0).toLocaleString()),
479
- });
480
- }
280
+ hoverTooltip(view, pos, side) {
281
+ if ( typeof this.editor.createTooltipWidget !== 'function' ) { return null; }
282
+ const details = view.domAtPos(pos);
283
+ const textNode = details.node;
284
+ if ( textNode.nodeType !== 3 ) { return null; }
285
+ const { parentElement } = textNode;
286
+ const targetElement = parentElement.closest('[data-tooltip]');
287
+ if ( targetElement === null ) { return null; }
288
+ const tooltipText = targetElement.getAttribute('data-tooltip');
289
+ if ( Boolean(tooltipText) === false ) { return null; }
290
+ const start = pos - details.offset;
291
+ const end = start + textNode.nodeValue.length;
292
+ if ( start === pos && side < 0 || end === pos && side > 0 ) { return null; }
293
+ return {
294
+ above: true,
295
+ pos: start,
296
+ end,
297
+ create: ( ) => {
298
+ return { dom: this.editor.createTooltipWidget(tooltipText) };
299
+ },
300
+ };
301
+ }
481
302
 
482
- function updateFeedbackPanel(info) {
483
- const errors = [];
484
- if ( Array.isArray(info.errors) ) {
485
- info.errors.forEach(e => errors.push(e));
303
+ foldService(state, from) {
304
+ if ( typeof this.editor.foldService !== 'function' ) { return null; }
305
+ return this.editor.foldService(state, from);
486
306
  }
487
- const text = errors.join('\n');
488
- self.cm6.showFeedbackPanel(cmRules, { template: '.feedback-panel', text });
489
- }
490
307
 
491
- /******************************************************************************/
308
+ // Details of YAML document(s) intersecting with a text span. If the text span
309
+ // starts on a YAML document divider, the previous YAML document will be
310
+ // included. If the text span ends on a YAML document divider, the next YAML
311
+ // document will be included.
492
312
 
493
- function importRulesFromFile() {
494
- const input = qs$('input[type="file"]');
495
- input.onchange = ev => {
496
- input.onchange = null;
497
- const file = ev.target.files[0];
498
- if ( file === undefined || file.name === '' ) { return; }
499
- if ( file.type !== 'application/json' ) { return; }
500
- const fr = new FileReader();
501
- fr.onload = ( ) => {
502
- if ( typeof fr.result !== 'string' ) { return; }
503
- const rules = rulesFromJSON(fr.result);
504
- if ( rules === undefined ) { return; }
505
- const text = textFromRules(rules);
506
- if ( text === undefined ) { return; }
507
- const { doc } = cmRules.state;
508
- const lastChars = doc.toString().trimEnd().slice(-4);
509
- const lastLine = doc.line(doc.lines);
510
- let from = lastLine.to;
511
- let prepend = '';
512
- if ( lastLine.text !== '' ) {
513
- prepend = '\n';
514
- } else {
515
- from = lastLine.from;
313
+ snapToYamlDocument(doc, start, end) {
314
+ let yamlDocStart = doc.lineAt(start).number;
315
+ if ( this.reYamlDocSeparator.test(doc.line(yamlDocStart).text) ) {
316
+ if ( yamlDocStart > 1 ) {
317
+ yamlDocStart -= 1;
516
318
  }
517
- if ( /(?:^|\n)---$/.test(lastChars) === false ) {
518
- prepend = `${prepend}---\n`;
319
+ }
320
+ while ( yamlDocStart > 1 ) {
321
+ const line = doc.line(yamlDocStart);
322
+ if ( this.reYamlDocSeparator.test(line.text) ) { break; }
323
+ yamlDocStart -= 1;
324
+ }
325
+ const lastLine = doc.lines;
326
+ let yamlDocEnd = doc.lineAt(end).number;
327
+ if ( this.reYamlDocSeparator.test(doc.line(yamlDocEnd).text) ) {
328
+ if ( yamlDocEnd < lastLine ) {
329
+ yamlDocEnd += 1;
519
330
  }
520
- cmRules.dispatch({ changes: { from, insert: `${prepend}${text}` } });
521
- self.cm6.foldAll(cmRules);
522
- cmRules.focus();
523
- };
524
- fr.readAsText(file);
525
- };
526
- // Reset to empty string, this will ensure a change event is properly
527
- // triggered if the user pick a file, even if it's the same as the last
528
- // one picked.
529
- input.value = '';
530
- input.click();
531
- }
532
-
533
- /******************************************************************************/
534
-
535
- function exportRulesToFile() {
536
- const text = getEditorText();
537
- const { rules } = rulesFromText(text);
538
- if ( Array.isArray(rules) === false ) { return; }
539
- let ruleId = 1;
540
- for ( const rule of rules ) {
541
- rule.id = ruleId++;
542
- }
543
- const filename = 'my-ubol-dnr-rules.json';
544
- const a = document.createElement('a');
545
- a.href = `data:application/json;charset=utf-8,${JSON.stringify(rules, null, 2)}`;
546
- dom.attr(a, 'download', filename || '');
547
- dom.attr(a, 'type', 'application/json');
548
- a.click();
549
- }
550
-
551
- /******************************************************************************/
552
-
553
- function importRulesFromPaste(transaction) {
554
- const { from, to } = rangeFromTransaction(transaction);
555
- if ( from === undefined || to === undefined ) { return; }
556
- // Paste position must match start of a line
557
- const { newDoc } = transaction;
558
- const lineFrom = newDoc.lineAt(from);
559
- if ( lineFrom.from !== from ) { return; }
560
- // Paste position must match a rule boundary
561
- if ( lineFrom.number !== 1 ) {
562
- const lineBefore = newDoc.line(lineFrom.number-1);
563
- if ( /^---\s*$/.test(lineBefore.text) === false ) { return; }
564
- }
565
- const pastedText = newDoc.sliceString(from, to);
566
- const rules = rulesFromJSON(pastedText);
567
- if ( rules === undefined ) { return; }
568
- const yamlText = textFromRules(rules);
569
- if ( yamlText === undefined ) { return; }
570
- cmRules.dispatch({ changes: { from, to, insert: yamlText } });
571
- self.cm6.foldAll(cmRules);
572
- return true;
573
- }
574
-
575
- /******************************************************************************/
576
-
577
- function foldService(state, from) {
578
- const { doc } = state;
579
- const lineFrom = doc.lineAt(from);
580
- if ( reFoldable.test(lineFrom.text) === false ) { return null; }
581
- if ( lineFrom.number <= 5 ) { return null ; }
582
- const lineBlockStart = doc.line(lineFrom.number - 5);
583
- if ( reFoldCandidates.test(lineBlockStart.text) === false ) { return null; }
584
- for ( let i = lineFrom.number-4; i < lineFrom.number; i++ ) {
585
- const line = doc.line(i);
586
- if ( reFoldable.test(line.text) === false ) { return null; }
587
- }
588
- let i = lineFrom.number + 1;
589
- for ( ; i <= doc.lines; i++ ) {
590
- const lineNext = doc.line(i);
591
- if ( reFoldable.test(lineNext.text) === false ) { break; }
592
- }
593
- i -= 1;
594
- if ( i === lineFrom.number ) { return null; }
595
- const lineFoldEnd = doc.line(i);
596
- return { from: lineFrom.from+6, to: lineFoldEnd.to };
597
- }
598
-
599
- const reFoldable = /^ {4}- \S/;
600
- const reFoldCandidates = new RegExp(`^(?: {2})+${[
601
- 'initiatorDomains',
602
- 'excludedInitiatorDomains',
603
- 'requestDomains',
604
- 'excludedRequestDomains',
605
- ].join('|')}:$`);
606
-
607
- /******************************************************************************/
608
-
609
- function smartBackspace(transaction) {
610
- const { from, to } = rangeFromTransaction(transaction);
611
- if ( from === undefined || to === undefined ) { return; }
612
- if ( to !== from ) { return; }
613
- const { newDoc } = transaction;
614
- const line = newDoc.lineAt(from);
615
- if ( /^(?: {2})+-$/.test(line.text) === false ) { return; }
616
- cmRules.dispatch({ changes: { from: from-3, to: from, insert: '' } });
617
- return true;
618
- }
619
-
620
- /******************************************************************************/
331
+ }
332
+ while ( yamlDocEnd < lastLine ) {
333
+ const line = doc.line(yamlDocEnd);
334
+ if ( this.reYamlDocSeparator.test(line.text) ) { break; }
335
+ yamlDocEnd += 1;
336
+ }
337
+ return { yamlDocStart, yamlDocEnd };
338
+ }
621
339
 
622
- function lineIsArrayItem(doc, lineNo) {
623
- if ( lineNo < 1 || lineNo > doc.lines ) { return false; }
624
- const line = doc.line(lineNo);
625
- return line.text.startsWith(' - ');
626
- }
340
+ rangeFromTransaction(transaction) {
341
+ let from, to;
342
+ transaction.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
343
+ if ( from === undefined || fromB < from ) { from = fromB; }
344
+ if ( to === undefined || toB > to ) { to = toB; }
345
+ });
346
+ return { from, to };
347
+ }
627
348
 
628
- /******************************************************************************/
349
+ addToModifiedRange(transaction) {
350
+ const { from, to } = this.rangeFromTransaction(transaction);
351
+ if ( from === undefined || to === undefined ) { return; }
352
+ const { newDoc } = transaction;
353
+ const { yamlDocStart, yamlDocEnd } = this.snapToYamlDocument(newDoc, from, to);
354
+ if ( this.modifiedRange.start === 0 || yamlDocStart < this.modifiedRange.start ) {
355
+ this.modifiedRange.start = yamlDocStart;
356
+ }
357
+ if ( this.modifiedRange.end === 0 || yamlDocEnd > this.modifiedRange.end ) {
358
+ this.modifiedRange.end = yamlDocEnd;
359
+ }
360
+ }
629
361
 
630
- function smartArrayItem(doc, from) {
631
- const line = doc.lineAt(from);
632
- if ( lineIsArrayItem(doc, line.number-1) === false ) {
633
- if ( lineIsArrayItem(doc, line.number+1) === false ) { return ''; }
362
+ lineIndentAt(line) {
363
+ const match = /^(?: {2})*/.exec(line.text);
364
+ const indent = match !== null ? match[0].length : -1;
365
+ if ( indent === -1 || (indent & 1) !== 0 ) { return -1; }
366
+ return indent / 2;
634
367
  }
635
- const blanks = /^ {2,4}$/.exec(line.text);
636
- if ( blanks === null ) { return ''; }
637
- const count = blanks[0].length;
638
- return `${' '.repeat(4-count)}- `;
639
- }
640
368
 
641
- /******************************************************************************/
369
+ getScopeAt(from, doc) {
370
+ doc ||= this.view.state.doc;
371
+ const lineFrom = doc.lineAt(from);
372
+ const out = {};
373
+ let depth = this.lineIndentAt(lineFrom);
374
+ if ( depth === -1 ) { return out; }
375
+ const text = lineFrom.text.trim();
376
+ if ( text.startsWith('#') ) { return out; }
377
+ const path = [];
378
+ const end = text.indexOf(':');
379
+ if ( end !== -1 ) {
380
+ const beg = text.startsWith('- ') ? 2 : 0;
381
+ path.push(text.slice(beg, end+1));
382
+ }
383
+ let lineNo = lineFrom.number;
384
+ while ( depth > 0 && lineNo > 1 ) {
385
+ lineNo -= 1;
386
+ const lineBefore = doc.line(lineNo);
387
+ const text = lineBefore.text.trim();
388
+ if ( text.startsWith('#') ) { continue; }
389
+ if ( this.lineIndentAt(lineBefore) > (depth-1) ) { continue; }
390
+ const match = /^- ([^:]+:)/.exec(text);
391
+ if ( match !== null ) {
392
+ path.unshift(match[1]);
393
+ } else {
394
+ path.unshift(text);
395
+ }
396
+ depth -= 1;
397
+ }
398
+ out.scope = path.join('');
399
+ out.depth = path.length;
400
+ return out;
401
+ }
642
402
 
643
- function smartReturn(transaction) {
644
- const { from, to } = rangeFromTransaction(transaction);
645
- if ( from === undefined || to === undefined ) { return; }
646
- const { newDoc } = transaction;
647
- const insert = smartArrayItem(newDoc, to);
648
- if ( insert === '' ) { return; }
649
- cmRules.dispatch({
650
- changes: { from: to, insert },
651
- selection: { anchor: to + insert.length },
652
- });
653
- return true;
654
- }
403
+ async saveEditorText() {
404
+ if ( typeof this.editor.saveEditorText !== 'function' ) { return; }
405
+ if ( this.editorTextChanged() === false ) { return; }
406
+ const saved = await this.editor.saveEditorText(this);
407
+ if ( saved !== true ) { return; }
408
+ this.lastSavedText = this.normalizeEditorText(this.getEditorText());
409
+ this.updateView();
410
+ }
655
411
 
656
- /******************************************************************************/
412
+ revertEditorText() {
413
+ if ( this.editorTextChanged() === false ) { return; }
414
+ this.setEditorText(this.lastSavedText);
415
+ }
657
416
 
658
- function smartSpacebar(transaction) {
659
- const { from, to } = rangeFromTransaction(transaction);
660
- if ( from === undefined || to === undefined ) { return; }
661
- if ( (to - from) !== 1 ) { return; }
662
- const { newDoc } = transaction;
663
- const line = newDoc.lineAt(to);
664
- const localTo = to - line.from;
665
- const before = line.text.slice(0, localTo);
666
- if ( /^(?: {1}| {3})$/.test(before) === false ) { return; }
667
- const insert = smartArrayItem(newDoc, to) || ' ';
668
- cmRules.dispatch({
669
- changes: { from: to, insert },
670
- selection: { anchor: to + insert.length },
671
- });
672
- return true;
673
- }
417
+ smartBackspace(transaction) {
418
+ const { from, to } = this.rangeFromTransaction(transaction);
419
+ if ( from === undefined || to === undefined ) { return; }
420
+ if ( to !== from ) { return; }
421
+ const { newDoc } = transaction;
422
+ const line = newDoc.lineAt(from);
423
+ if ( /^(?: {2})+-$/.test(line.text) === false ) { return; }
424
+ this.view.dispatch({ changes: { from: from-3, to: from, insert: '' } });
425
+ return true;
426
+ }
674
427
 
675
- /******************************************************************************/
428
+ lineIsArrayItem(doc, lineNo) {
429
+ if ( lineNo < 1 || lineNo > doc.lines ) { return false; }
430
+ const line = doc.line(lineNo);
431
+ return /^(?: {2})+- /.test(line.text);
432
+ }
676
433
 
677
- const dnryamlStreamParser = {
678
- name: 'dnryaml',
679
- startState() {
680
- return {
681
- scope: 0,
682
- reKeywords: new RegExp(`\\b(${[
683
- 'block',
684
- 'redirect',
685
- 'allow',
686
- 'modifyHeaders',
687
- 'upgradeScheme',
688
- 'allowAllRequest',
689
- 'append',
690
- 'set',
691
- 'remove',
692
- 'firstParty',
693
- 'thirdParty',
694
- 'true',
695
- 'false',
696
- 'connect',
697
- 'delete',
698
- 'get',
699
- 'head',
700
- 'options',
701
- 'patch',
702
- 'post',
703
- 'put',
704
- 'other',
705
- 'main_frame',
706
- 'sub_frame',
707
- 'stylesheet',
708
- 'script',
709
- 'image',
710
- 'font',
711
- 'object',
712
- 'xmlhttprequest',
713
- 'ping',
714
- 'csp_report',
715
- 'media',
716
- 'websocket',
717
- 'webtransport',
718
- 'webbundle',
719
- 'other',
720
- ].join('|')})\\b`),
721
- };
722
- },
723
- token(stream, state) {
724
- const c = stream.peek();
725
- if ( c === '#' ) {
726
- if ( (stream.pos === 0 || /\s/.test(stream.string.charAt(stream.pos - 1))) ) {
727
- stream.skipToEnd();
728
- return 'comment';
434
+ smartArrayItem(doc, from) {
435
+ const line = doc.lineAt(from);
436
+ if ( line.from === 0 ) { return; }
437
+ const blanks = /^ *$/.exec(line.text);
438
+ if ( blanks === null ) { return; }
439
+ if ( this.editor.newlineAssistant ) {
440
+ const { scope } = this.getScopeAt(line.from-1, doc);
441
+ const insert = this.editor.newlineAssistant[scope];
442
+ if ( insert ) {
443
+ this.view.dispatch({
444
+ changes: { from: line.from, to: line.to, insert },
445
+ selection: { anchor: line.from + insert.length },
446
+ });
447
+ return true;
729
448
  }
730
449
  }
731
- if ( stream.sol() ) {
732
- if ( stream.match('---') ) { return 'contentSeparator'; }
733
- if ( stream.match('...') ) { return 'contentSeparator'; }
734
- }
735
- if ( stream.eatSpace() ) {
736
- return null;
737
- }
738
- const { scope } = state;
739
- state.scope = 0;
740
- if ( scope === 0 && stream.match(/^[^:]+(?=:)/) ) {
741
- state.scope = 1;
742
- return 'keyword';
450
+ let targetIndent;
451
+ if ( this.lineIsArrayItem(doc, line.number-1) ) {
452
+ targetIndent = doc.line(line.number-1).text.indexOf('- ');
453
+ } else if ( this.lineIsArrayItem(doc, line.number+1) ) {
454
+ targetIndent = doc.line(line.number+1).text.indexOf('- ');
743
455
  }
744
- if ( scope === 1 && stream.match(/^:(?: |$)/) ) {
745
- return 'meta';
746
- }
747
- if ( stream.match(/^- /) ) {
748
- return 'meta';
749
- }
750
- if ( stream.match(state.reKeywords) ) {
751
- return 'literal';
752
- }
753
- if ( stream.match(/^\S+/) ) {
754
- return null;
755
- }
756
- stream.next();
757
- return null;
758
- },
759
- };
760
-
761
- /******************************************************************************/
456
+ if ( targetIndent === undefined ) { return; }
457
+ const indent = targetIndent - blanks[0].length;
458
+ if ( indent < 0 || indent > 2 ) { return; }
459
+ const insert = `${' '.repeat(indent)}- `;
460
+ this.view.dispatch({
461
+ changes: { from, insert },
462
+ selection: { anchor: from + insert.length },
463
+ });
464
+ return true;
465
+ }
762
466
 
763
- function cmUpdateListener(info) {
764
- if ( info.docChanged === false ) { return; }
765
- for ( const transaction of info.transactions ) {
766
- if ( transaction.docChanged === false ) { continue; }
767
- addToModifiedRange(transaction);
768
- if ( transaction.isUserEvent('delete.backward') ) {
769
- smartBackspace(transaction);
770
- } else if ( transaction.isUserEvent('input.paste') ) {
771
- importRulesFromPaste(transaction);
772
- } else if ( transaction.isUserEvent('input') ) {
773
- if ( smartReturn(transaction) ) { continue; }
774
- smartSpacebar(transaction);
775
- }
467
+ smartReturn(transaction) {
468
+ const { from, to } = this.rangeFromTransaction(transaction);
469
+ if ( from === undefined || to === undefined ) { return; }
470
+ const { newDoc } = transaction;
471
+ return this.smartArrayItem(newDoc, to);
776
472
  }
777
- updateViewAsync();
778
- }
779
473
 
780
- /******************************************************************************/
474
+ smartSpacebar(transaction) {
475
+ const { from, to } = this.rangeFromTransaction(transaction);
476
+ if ( from === undefined || to === undefined ) { return; }
477
+ if ( (to - from) !== 1 ) { return; }
478
+ const { newDoc } = transaction;
479
+ const line = newDoc.lineAt(to);
480
+ const localTo = to - line.from;
481
+ const before = line.text.slice(0, localTo);
482
+ if ( /^(?: {1}| {3})$/.test(before) === false ) { return; }
483
+ if ( this.smartArrayItem(newDoc, to) ) { return true; }
484
+ this.view.dispatch({
485
+ changes: { from: to, insert: ' ' },
486
+ selection: { anchor: to + 1 },
487
+ });
488
+ return true;
489
+ }
781
490
 
782
- function gutterClick(view, info) {
783
- const reSeparator = /^---\s*/;
784
- const { doc } = view.state;
785
- const lineFirst = doc.lineAt(info.from);
786
- if ( lineFirst.text === '' ) { return false; }
787
- let { from, to } = lineFirst;
788
- if ( reSeparator.test(lineFirst.text) ) {
789
- let lineNo = lineFirst.number + 1;
790
- while ( lineNo < doc.lines ) {
791
- const line = doc.line(lineNo);
792
- if ( reSeparator.test(line.text) ) { break; }
793
- to = line.to;
794
- lineNo += 1;
491
+ gutterClick(view, info) {
492
+ const reSeparator = /^(?:---|# ---)\s*/;
493
+ const { doc } = view.state;
494
+ const lineFirst = doc.lineAt(info.from);
495
+ if ( lineFirst.text === '' ) { return false; }
496
+ let { from, to } = lineFirst;
497
+ if ( reSeparator.test(lineFirst.text) ) {
498
+ let lineNo = lineFirst.number + 1;
499
+ while ( lineNo < doc.lines ) {
500
+ const line = doc.line(lineNo);
501
+ if ( reSeparator.test(line.text) ) { break; }
502
+ to = line.to;
503
+ lineNo += 1;
504
+ }
795
505
  }
506
+ view.dispatch({
507
+ selection: { anchor: from, head: to+1 }
508
+ });
509
+ view.focus();
510
+ return true;
796
511
  }
797
- view.dispatch({
798
- selection: { anchor: from, head: to+1 }
799
- });
800
- view.focus();
801
- return true;
802
- }
803
512
 
804
- /******************************************************************************/
513
+ importFromFile() {
514
+ const editor = this.editor;
515
+ if ( typeof editor.importFromFile !== 'function' ) { return; }
516
+ const input = qs$('input[type="file"]');
517
+ input.accept = editor.ioAccept || '';
518
+ input.onchange = ev => {
519
+ input.onchange = null;
520
+ const file = ev.target.files[0];
521
+ if ( file === undefined || file.name === '' ) { return; }
522
+ const fr = new FileReader();
523
+ fr.onload = ( ) => {
524
+ if ( typeof fr.result !== 'string' ) { return; }
525
+ editor.importFromFile(this, fr.result);
526
+ };
527
+ fr.readAsText(file);
528
+ };
529
+ // Reset to empty string, this will ensure a change event is properly
530
+ // triggered if the user pick a file, even if it's the same as the last
531
+ // one picked.
532
+ input.value = '';
533
+ input.click();
534
+ }
805
535
 
806
- function hoverTooltip(view, pos, side) {
807
- const details = view.domAtPos(pos);
808
- const textNode = details.node;
809
- if ( textNode.nodeType !== 3 ) { return null; }
810
- const { parentElement } = textNode;
811
- const targetElement = parentElement.closest('[data-tooltip]');
812
- if ( targetElement === null ) { return null; }
813
- const tooltipText = targetElement.getAttribute('data-tooltip');
814
- if ( Boolean(tooltipText) === false ) { return null; }
815
- const start = pos - details.offset;
816
- const end = start + textNode.nodeValue.length;
817
- if ( start === pos && side < 0 || end === pos && side > 0 ) { return null; }
818
- return {
819
- above: true,
820
- pos: start,
821
- end,
822
- create() {
823
- const template = document.querySelector('.badmark-tooltip');
824
- const fragment = template.content.cloneNode(true);
825
- const dom = fragment.querySelector('.badmark-tooltip');
826
- dom.textContent = tooltipText;
827
- return { dom };
536
+ exportToFile() {
537
+ const editor = this.editor;
538
+ if ( typeof editor.exportToFile !== 'function' ) { return; }
539
+ const text = this.getEditorText();
540
+ const result = editor.exportToFile(text);
541
+ if ( result === undefined ) { return; }
542
+ const { fname, data, mime } = result;
543
+ const a = document.createElement('a');
544
+ a.href = `data:${mime};charset=utf-8,${encodeURIComponent(data)}`;
545
+ dom.attr(a, 'download', fname || '');
546
+ dom.attr(a, 'type', mime);
547
+ a.click();
548
+ }
549
+
550
+ streamParser = {
551
+ startState: ( ) => {
552
+ return { scope: 0 };
553
+ },
554
+ token: (stream, state) => {
555
+ if ( stream.sol() ) {
556
+ if ( stream.match(/^---\s*$/) ) { return 'meta'; }
557
+ if ( stream.match(/^# ---\s*$/) ) { return 'meta comment'; }
558
+ if ( stream.match(/\.\.\.\s*$/) ) { return 'meta'; }
559
+ }
560
+ const c = stream.peek();
561
+ if ( c === '#' ) {
562
+ if ( (stream.pos === 0 || /\s/.test(stream.string.charAt(stream.pos - 1))) ) {
563
+ stream.skipToEnd();
564
+ return 'comment';
565
+ }
566
+ }
567
+ if ( stream.eatSpace() ) {
568
+ return null;
569
+ }
570
+ const { scope } = state;
571
+ state.scope = 0;
572
+ if ( scope === 0 && stream.match(/^[^:]+(?=:)/) ) {
573
+ state.scope = 1;
574
+ return 'keyword';
575
+ }
576
+ if ( scope === 1 && stream.match(/^:(?: |$)/) ) {
577
+ return 'punctuation';
578
+ }
579
+ if ( stream.match(/^- /) ) {
580
+ return 'punctuation';
581
+ }
582
+ if ( this.editor.streamParserKeywords ) {
583
+ if ( stream.match(this.editor.streamParserKeywords) ) {
584
+ return 'literal';
585
+ }
586
+ }
587
+ if ( stream.match(/^\S+/) ) {
588
+ return null;
589
+ }
590
+ stream.next();
591
+ return null;
592
+ },
593
+ languageData: {
594
+ commentTokens: { line: '#' },
828
595
  },
829
596
  };
830
597
  }
831
598
 
832
599
  /******************************************************************************/
833
600
 
834
- let lastSavedText = '';
835
-
836
- const cmRules = await localRead('userDnrRules').then(text => {
837
- text ||= '';
838
-
839
- const view = self.cm6.createEditorView({
840
- text,
841
- dnrRules: true,
842
- oneDark: dom.cl.has(':root', 'dark'),
843
- updateListener: cmUpdateListener,
844
- saveListener: ( ) => {
845
- saveEditorText();
846
- },
847
- lineError: true,
848
- spanError: true,
849
- // https://codemirror.net/examples/autocompletion/
850
- autocompletion: {
851
- override: [ autoComplete ],
852
- activateOnCompletion: ( ) => true,
853
- },
854
- gutterClick,
855
- hoverTooltip,
856
- streamParser: dnryamlStreamParser,
857
- foldService,
858
- }, qs$('#cm-dnrRules'));
859
-
860
- lastSavedText = text;
861
- self.cm6.foldAll(view);
862
- self.cm6.resetUndoRedo(view);
863
-
864
- browser.storage.onChanged.addListener((changes, area) => {
865
- if ( area !== 'local' ) { return; }
866
- const { userDnrRuleCount } = changes;
867
- if ( userDnrRuleCount instanceof Object === false ) { return; }
868
- const { newValue } = changes.userDnrRuleCount;
869
- updateSummaryPanel({ userDnrRuleCount: newValue });
870
- });
871
-
872
- localRead('userDnrRuleCount').then(userDnrRuleCount => {
873
- updateSummaryPanel({ userDnrRuleCount })
601
+ async function start() {
602
+ const editor = new Editor();
603
+ await editor.init();
604
+ dom.on('#editors', 'change', ( ) => {
605
+ const select = qs$('#editors');
606
+ const mode = select.value;
607
+ if ( mode === editor.mode ) { return; }
608
+ editor.selectEditor(mode);
609
+ localWrite('dashboard.develop.editor', editor.mode);
874
610
  });
611
+ }
875
612
 
876
- dom.on('#dnrRulesApply', 'click', ( ) => {
877
- saveEditorText();
878
- });
879
- dom.on('#dnrRulesRevert', 'click', ( ) => {
880
- setEditorText(lastSavedText);
881
- sendMessage({ what: 'updateUserDnrRules' });
882
- });
883
- dom.on('#dnrRulesImport', 'click', importRulesFromFile);
884
- dom.on('#dnrRulesExport', 'click', exportRulesToFile);
885
-
886
- return view;
613
+ let observer = new IntersectionObserver(entries => {
614
+ for ( const entry of entries ) {
615
+ if ( entry.isIntersecting === false ) { continue; }
616
+ start();
617
+ observer.disconnect();
618
+ observer = null;
619
+ break;
620
+ }
887
621
  });
622
+ observer.observe(qs$('section[data-pane="develop"]'));
888
623
 
889
624
  /******************************************************************************/