sourcemonkey 0.0.0-stage → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (367) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +87 -2
  3. package/dist/bytes.js +37 -0
  4. package/dist/channel-placeholder.js +5 -0
  5. package/dist/collection-scan.js +17 -0
  6. package/dist/collections.html +353 -0
  7. package/dist/compare.html +358 -0
  8. package/dist/composed-source.js +205 -0
  9. package/dist/connect-prompt.html +47 -0
  10. package/dist/debug/icons.html +211 -0
  11. package/dist/debug/storage.html +163 -0
  12. package/dist/debug-log.js +75 -0
  13. package/dist/diagnostic-location.js +64 -0
  14. package/dist/eval-hook.js +308 -0
  15. package/dist/extension/background.js +5263 -0
  16. package/dist/extension/channel.js +133 -0
  17. package/dist/extension/code-links.js +187 -0
  18. package/dist/extension/code-tabs.js +460 -0
  19. package/dist/extension/collection-dialog.js +619 -0
  20. package/dist/extension/collection-display.js +322 -0
  21. package/dist/extension/collections.js +2905 -0
  22. package/dist/extension/compare.js +867 -0
  23. package/dist/extension/concurrency.js +186 -0
  24. package/dist/extension/connect-grants.js +109 -0
  25. package/dist/extension/connect-prompt-page.js +70 -0
  26. package/dist/extension/connect-prompt.js +266 -0
  27. package/dist/extension/copy-button.js +63 -0
  28. package/dist/extension/copy-dialog.js +502 -0
  29. package/dist/extension/copy-preference.js +66 -0
  30. package/dist/extension/debug/icons.js +203 -0
  31. package/dist/extension/debug/storage.js +365 -0
  32. package/dist/extension/deep-link.js +77 -0
  33. package/dist/extension/delete-dialog.js +432 -0
  34. package/dist/extension/delete-icon.js +40 -0
  35. package/dist/extension/details-tooltips.js +66 -0
  36. package/dist/extension/directories.js +679 -0
  37. package/dist/extension/export-backup.js +407 -0
  38. package/dist/extension/export-dialog.js +142 -0
  39. package/dist/extension/file-access.js +74 -0
  40. package/dist/extension/file-changes.js +346 -0
  41. package/dist/extension/frame-info.js +85 -0
  42. package/dist/extension/github-provider.js +336 -0
  43. package/dist/extension/glyph.js +84 -0
  44. package/dist/extension/gm-bindings.js +601 -0
  45. package/dist/extension/gm-download.js +419 -0
  46. package/dist/extension/gm-menu.js +228 -0
  47. package/dist/extension/gm-notification.js +141 -0
  48. package/dist/extension/gm-originator-map.js +23 -0
  49. package/dist/extension/gm-tab-data.js +121 -0
  50. package/dist/extension/gm-tab.js +160 -0
  51. package/dist/extension/gm-url-change.js +111 -0
  52. package/dist/extension/gm-url-scheme.js +27 -0
  53. package/dist/extension/gm-values.js +176 -0
  54. package/dist/extension/gm-window-control.js +104 -0
  55. package/dist/extension/gm-xhr-headers.js +333 -0
  56. package/dist/extension/gm-xhr.js +584 -0
  57. package/dist/extension/injector.js +3145 -0
  58. package/dist/extension/install-capture.js +277 -0
  59. package/dist/extension/line-diff.js +233 -0
  60. package/dist/extension/local-copy.js +560 -0
  61. package/dist/extension/local-delete.js +276 -0
  62. package/dist/extension/location-kinds.js +108 -0
  63. package/dist/extension/log-format.js +158 -0
  64. package/dist/extension/managed-changes.js +361 -0
  65. package/dist/extension/managed-items.js +57 -0
  66. package/dist/extension/match-index.js +375 -0
  67. package/dist/extension/missing-scripts.js +66 -0
  68. package/dist/extension/more-menu.js +109 -0
  69. package/dist/extension/move-dialog.js +197 -0
  70. package/dist/extension/offscreen.js +37 -0
  71. package/dist/extension/options.js +504 -0
  72. package/dist/extension/page-heading.js +170 -0
  73. package/dist/extension/page-links.js +199 -0
  74. package/dist/extension/parse-check-client.js +70 -0
  75. package/dist/extension/parse-check.js +161 -0
  76. package/dist/extension/parse-sandbox-host.js +172 -0
  77. package/dist/extension/parse-sandbox.js +175 -0
  78. package/dist/extension/popup-commands-open.js +41 -0
  79. package/dist/extension/popup-view.js +387 -0
  80. package/dist/extension/popup.js +703 -0
  81. package/dist/extension/prism-userscript.js +53 -0
  82. package/dist/extension/refresh-error.js +136 -0
  83. package/dist/extension/refresh-targets.js +160 -0
  84. package/dist/extension/related-versions.js +1144 -0
  85. package/dist/extension/resize-observer-loop.js +19 -0
  86. package/dist/extension/row-cache.js +387 -0
  87. package/dist/extension/script-blobs.js +413 -0
  88. package/dist/extension/script-details.js +658 -0
  89. package/dist/extension/script-enablement.js +285 -0
  90. package/dist/extension/script-identity.js +310 -0
  91. package/dist/extension/script-keys.js +54 -0
  92. package/dist/extension/script-log-id.js +155 -0
  93. package/dist/extension/script-log.js +290 -0
  94. package/dist/extension/script-rejection.js +104 -0
  95. package/dist/extension/script-sites.js +158 -0
  96. package/dist/extension/script-store.js +3507 -0
  97. package/dist/extension/script-updater.js +991 -0
  98. package/dist/extension/script-url-hash.js +61 -0
  99. package/dist/extension/select-all.js +37 -0
  100. package/dist/extension/select-open-guard.js +90 -0
  101. package/dist/extension/site-icon.js +1261 -0
  102. package/dist/extension/sm-dev-link.js +302 -0
  103. package/dist/extension/solo-click.js +58 -0
  104. package/dist/extension/sticky-numbers.js +188 -0
  105. package/dist/extension/storage-breakdown.js +253 -0
  106. package/dist/extension/storage-scan.js +86 -0
  107. package/dist/extension/storage-usage.js +194 -0
  108. package/dist/extension/structural-keys.js +29 -0
  109. package/dist/extension/sw-teardown.js +36 -0
  110. package/dist/extension/tab-status.js +403 -0
  111. package/dist/extension/toolbar-summary.js +105 -0
  112. package/dist/extension/user-scripts-access.js +43 -0
  113. package/dist/extension/userscript.js +3672 -0
  114. package/dist/extension/value-store.js +204 -0
  115. package/dist/extension/version-probe-fetch.js +68 -0
  116. package/dist/extension/worker-client.js +109 -0
  117. package/dist/extension/worker-ops.js +171 -0
  118. package/dist/extension/zip-writer.js +24 -0
  119. package/dist/external-files.js +878 -0
  120. package/dist/file-loader.js +436 -0
  121. package/dist/file-locations.js +439 -0
  122. package/dist/generated-wrappers.js +5 -0
  123. package/dist/github-auth.js +148 -0
  124. package/dist/github-urls.js +46 -0
  125. package/dist/gm-api-catalog.js +217 -0
  126. package/dist/gm-connect.js +273 -0
  127. package/dist/gm-xhr-types.js +5 -0
  128. package/dist/http-read.js +142 -0
  129. package/dist/icons/icon-128.png +0 -0
  130. package/dist/icons/icon-16.png +0 -0
  131. package/dist/icons/icon-48.png +0 -0
  132. package/dist/local-file-overrides.js +558 -0
  133. package/dist/manifest.json +38 -0
  134. package/dist/markup-response.js +126 -0
  135. package/dist/match-targets.js +305 -0
  136. package/dist/menu-captions.js +22 -0
  137. package/dist/offscreen.html +39 -0
  138. package/dist/options.html +197 -0
  139. package/dist/parse-check-protocol.js +51 -0
  140. package/dist/parse-location.js +171 -0
  141. package/dist/parse-sandbox.html +56 -0
  142. package/dist/phase-timing.js +155 -0
  143. package/dist/popup.html +197 -0
  144. package/dist/public-suffixes.js +6957 -0
  145. package/dist/run-context.js +31 -0
  146. package/dist/runtime-messages.js +34 -0
  147. package/dist/sandboxed-page.js +35 -0
  148. package/dist/script-build.js +787 -0
  149. package/dist/script-display.js +383 -0
  150. package/dist/script-icon.js +43 -0
  151. package/dist/script-links.js +204 -0
  152. package/dist/script-source-url.js +214 -0
  153. package/dist/script-world.js +65 -0
  154. package/dist/sm-dev-protocol.js +84 -0
  155. package/dist/source-map.js +177 -0
  156. package/dist/stack-link.js +138 -0
  157. package/dist/styles.css +825 -0
  158. package/dist/unsafe-window-use.js +229 -0
  159. package/dist/url-match.js +734 -0
  160. package/dist/userscript-header.js +248 -0
  161. package/dist/userscript.html +1165 -0
  162. package/dist/vendor/fflate.LICENSE +21 -0
  163. package/dist/vendor/fflate.js +2692 -0
  164. package/dist/vendor/prism/prism-line-numbers.css +1 -0
  165. package/dist/vendor/prism/prism-line-numbers.js +1 -0
  166. package/dist/vendor/prism/prism.css +1 -0
  167. package/dist/vendor/prism/prism.js +1946 -0
  168. package/dist/version-compare.js +141 -0
  169. package/dist/version-probe.js +120 -0
  170. package/lib/build-info.json +1 -0
  171. package/lib/bytes.d.ts +3 -0
  172. package/lib/bytes.js +37 -0
  173. package/lib/channel-placeholder.d.ts +1 -0
  174. package/lib/channel-placeholder.js +5 -0
  175. package/lib/collection-scan.d.ts +8 -0
  176. package/lib/collection-scan.js +17 -0
  177. package/lib/composed-source.d.ts +28 -0
  178. package/lib/composed-source.js +205 -0
  179. package/lib/debug-log.d.ts +9 -0
  180. package/lib/debug-log.js +75 -0
  181. package/lib/diagnostic-location.d.ts +8 -0
  182. package/lib/diagnostic-location.js +64 -0
  183. package/lib/eval-hook.d.ts +34 -0
  184. package/lib/eval-hook.js +308 -0
  185. package/lib/external-files.d.ts +111 -0
  186. package/lib/external-files.js +878 -0
  187. package/lib/file-loader.d.ts +48 -0
  188. package/lib/file-loader.js +436 -0
  189. package/lib/file-locations.d.ts +44 -0
  190. package/lib/file-locations.js +439 -0
  191. package/lib/generated-wrappers.d.ts +11 -0
  192. package/lib/generated-wrappers.js +5 -0
  193. package/lib/github-auth.d.ts +12 -0
  194. package/lib/github-auth.js +148 -0
  195. package/lib/github-urls.d.ts +1 -0
  196. package/lib/github-urls.js +46 -0
  197. package/lib/gm-api-catalog.d.ts +24 -0
  198. package/lib/gm-api-catalog.js +217 -0
  199. package/lib/gm-connect.d.ts +34 -0
  200. package/lib/gm-connect.js +273 -0
  201. package/lib/gm-xhr-types.d.ts +68 -0
  202. package/lib/gm-xhr-types.js +5 -0
  203. package/lib/harness/browser-extensions.d.ts +73 -0
  204. package/lib/harness/browser-extensions.js +285 -0
  205. package/lib/harness/browser-lang.d.ts +20 -0
  206. package/lib/harness/browser-lang.js +86 -0
  207. package/lib/harness/browser-launch.d.ts +14 -0
  208. package/lib/harness/browser-launch.js +184 -0
  209. package/lib/harness/checks.d.ts +110 -0
  210. package/lib/harness/checks.js +321 -0
  211. package/lib/harness/cli.d.ts +2 -0
  212. package/lib/harness/cli.js +2259 -0
  213. package/lib/harness/command-args.d.ts +91 -0
  214. package/lib/harness/command-args.js +369 -0
  215. package/lib/harness/command-lines.d.ts +80 -0
  216. package/lib/harness/command-lines.js +180 -0
  217. package/lib/harness/command-list.d.ts +206 -0
  218. package/lib/harness/command-list.js +1475 -0
  219. package/lib/harness/console-commands.d.ts +463 -0
  220. package/lib/harness/console-commands.js +3216 -0
  221. package/lib/harness/download-watch.d.ts +21 -0
  222. package/lib/harness/download-watch.js +156 -0
  223. package/lib/harness/extension-backend.d.ts +41 -0
  224. package/lib/harness/extension-backend.js +100 -0
  225. package/lib/harness/extension-host.d.ts +112 -0
  226. package/lib/harness/extension-host.js +552 -0
  227. package/lib/harness/extension-launch.d.ts +67 -0
  228. package/lib/harness/extension-launch.js +285 -0
  229. package/lib/harness/extension-link.d.ts +315 -0
  230. package/lib/harness/extension-link.js +607 -0
  231. package/lib/harness/external-manager.d.ts +146 -0
  232. package/lib/harness/external-manager.js +414 -0
  233. package/lib/harness/fixture.d.ts +165 -0
  234. package/lib/harness/fixture.js +461 -0
  235. package/lib/harness/frame-sessions.d.ts +71 -0
  236. package/lib/harness/frame-sessions.js +248 -0
  237. package/lib/harness/frames.d.ts +68 -0
  238. package/lib/harness/frames.js +216 -0
  239. package/lib/harness/help-format.d.ts +17 -0
  240. package/lib/harness/help-format.js +127 -0
  241. package/lib/harness/host.d.ts +352 -0
  242. package/lib/harness/host.js +423 -0
  243. package/lib/harness/index.d.ts +8 -0
  244. package/lib/harness/index.js +10 -0
  245. package/lib/harness/input-file.d.ts +18 -0
  246. package/lib/harness/input-file.js +61 -0
  247. package/lib/harness/json-output.d.ts +565 -0
  248. package/lib/harness/json-output.js +71 -0
  249. package/lib/harness/manager-actions.d.ts +21 -0
  250. package/lib/harness/manager-actions.js +129 -0
  251. package/lib/harness/manager-commands.d.ts +142 -0
  252. package/lib/harness/manager-commands.js +1196 -0
  253. package/lib/harness/manager-fetch.d.ts +33 -0
  254. package/lib/harness/manager-fetch.js +239 -0
  255. package/lib/harness/managers.d.ts +24 -0
  256. package/lib/harness/managers.js +27 -0
  257. package/lib/harness/output-style.d.ts +125 -0
  258. package/lib/harness/output-style.js +322 -0
  259. package/lib/harness/page-commands.d.ts +134 -0
  260. package/lib/harness/page-commands.js +1141 -0
  261. package/lib/harness/page-output.d.ts +67 -0
  262. package/lib/harness/page-output.js +139 -0
  263. package/lib/harness/page-watch.d.ts +171 -0
  264. package/lib/harness/page-watch.js +607 -0
  265. package/lib/harness/parse-check-node.d.ts +3 -0
  266. package/lib/harness/parse-check-node.js +132 -0
  267. package/lib/harness/path-args.d.ts +22 -0
  268. package/lib/harness/path-args.js +148 -0
  269. package/lib/harness/playwright-chromium.d.ts +16 -0
  270. package/lib/harness/playwright-chromium.js +86 -0
  271. package/lib/harness/prepare.d.ts +168 -0
  272. package/lib/harness/prepare.js +364 -0
  273. package/lib/harness/prompt-editor.d.ts +17 -0
  274. package/lib/harness/prompt-editor.js +354 -0
  275. package/lib/harness/prompt-history.d.ts +13 -0
  276. package/lib/harness/prompt-history.js +89 -0
  277. package/lib/harness/rebuild-advice.d.ts +6 -0
  278. package/lib/harness/rebuild-advice.js +39 -0
  279. package/lib/harness/run-log.d.ts +47 -0
  280. package/lib/harness/run-log.js +140 -0
  281. package/lib/harness/run-logs.d.ts +132 -0
  282. package/lib/harness/run-logs.js +241 -0
  283. package/lib/harness/run.d.ts +194 -0
  284. package/lib/harness/run.js +1973 -0
  285. package/lib/harness/runs.d.ts +229 -0
  286. package/lib/harness/runs.js +726 -0
  287. package/lib/harness/save-html.d.ts +39 -0
  288. package/lib/harness/save-html.js +89 -0
  289. package/lib/harness/saved-pages.d.ts +120 -0
  290. package/lib/harness/saved-pages.js +275 -0
  291. package/lib/harness/script-mark.d.ts +17 -0
  292. package/lib/harness/script-mark.js +56 -0
  293. package/lib/harness/snapshot.d.ts +143 -0
  294. package/lib/harness/snapshot.js +474 -0
  295. package/lib/harness/stuck-tabs.d.ts +19 -0
  296. package/lib/harness/stuck-tabs.js +131 -0
  297. package/lib/harness/tab-refs.d.ts +20 -0
  298. package/lib/harness/tab-refs.js +80 -0
  299. package/lib/harness/tampermonkey.d.ts +71 -0
  300. package/lib/harness/tampermonkey.js +356 -0
  301. package/lib/harness/tm-ids.d.ts +18 -0
  302. package/lib/harness/tm-ids.js +88 -0
  303. package/lib/harness/violentmonkey.d.ts +34 -0
  304. package/lib/harness/violentmonkey.js +162 -0
  305. package/lib/harness/wait.d.ts +77 -0
  306. package/lib/harness/wait.js +458 -0
  307. package/lib/http-read.d.ts +30 -0
  308. package/lib/http-read.js +142 -0
  309. package/lib/local-file-overrides.d.ts +35 -0
  310. package/lib/local-file-overrides.js +558 -0
  311. package/lib/manifest.json +38 -0
  312. package/lib/markup-response.d.ts +11 -0
  313. package/lib/markup-response.js +126 -0
  314. package/lib/match-targets.d.ts +18 -0
  315. package/lib/match-targets.js +305 -0
  316. package/lib/menu-captions.d.ts +1 -0
  317. package/lib/menu-captions.js +22 -0
  318. package/lib/parse-check-protocol.d.ts +27 -0
  319. package/lib/parse-check-protocol.js +51 -0
  320. package/lib/parse-location.d.ts +12 -0
  321. package/lib/parse-location.js +171 -0
  322. package/lib/phase-timing.d.ts +12 -0
  323. package/lib/phase-timing.js +155 -0
  324. package/lib/public-suffixes.d.ts +1 -0
  325. package/lib/public-suffixes.js +6957 -0
  326. package/lib/run-context.d.ts +2 -0
  327. package/lib/run-context.js +31 -0
  328. package/lib/runtime-messages.d.ts +10 -0
  329. package/lib/runtime-messages.js +34 -0
  330. package/lib/sandboxed-page.d.ts +5 -0
  331. package/lib/sandboxed-page.js +35 -0
  332. package/lib/script-build.d.ts +111 -0
  333. package/lib/script-build.js +787 -0
  334. package/lib/script-display.d.ts +51 -0
  335. package/lib/script-display.js +383 -0
  336. package/lib/script-icon.d.ts +16 -0
  337. package/lib/script-icon.js +43 -0
  338. package/lib/script-links.d.ts +24 -0
  339. package/lib/script-links.js +204 -0
  340. package/lib/script-source-url.d.ts +8 -0
  341. package/lib/script-source-url.js +214 -0
  342. package/lib/script-world.d.ts +6 -0
  343. package/lib/script-world.js +65 -0
  344. package/lib/sm-dev-protocol.d.ts +251 -0
  345. package/lib/sm-dev-protocol.js +84 -0
  346. package/lib/source-map.d.ts +32 -0
  347. package/lib/source-map.js +177 -0
  348. package/lib/stack-link.d.ts +15 -0
  349. package/lib/stack-link.js +138 -0
  350. package/lib/unsafe-window-use.d.ts +1 -0
  351. package/lib/unsafe-window-use.js +229 -0
  352. package/lib/url-match.d.ts +40 -0
  353. package/lib/url-match.js +734 -0
  354. package/lib/userscript-header.d.ts +33 -0
  355. package/lib/userscript-header.js +248 -0
  356. package/lib/version-compare.d.ts +6 -0
  357. package/lib/version-compare.js +141 -0
  358. package/lib/version-probe.d.ts +17 -0
  359. package/lib/version-probe.js +120 -0
  360. package/package.json +55 -3
  361. package/skills/SourceMonkey-dev/SKILL.md +868 -0
  362. package/skills/SourceMonkey-dev/references/cdp.md +293 -0
  363. package/skills/SourceMonkey-dev/references/commands.md +297 -0
  364. package/skills/SourceMonkey-dev/references/other-managers.md +63 -0
  365. package/skills/SourceMonkey-dev/references/specs.md +46 -0
  366. package/skills/SourceMonkey-friction/SKILL.md +103 -0
  367. package/skills/SourceMonkey-friction/references/template.md +59 -0
@@ -0,0 +1,248 @@
1
+ // Parser for the Tampermonkey-style metadata block at the top of a
2
+ // userscript:
3
+ //
4
+ // // ==UserScript==
5
+ // // @name Hello
6
+ // // @match https://example.com/*
7
+ // // @grant none
8
+ // // ==/UserScript==
9
+ //
10
+ // We return a flat list of `{tag, locale?, value}` entries in source
11
+ // order so callers can decide which tags are single-valued (@name,
12
+ // @version) and which can repeat (@match, @grant, @require, …) without
13
+ // the parser baking that policy in. Tag names are lowercased so lookups
14
+ // are case-insensitive; locales like `@name:de` are kept on the side.
15
+ // Every line-terminator shape the metadata-block scanner recognizes.
16
+ // One definition so "which line is this tag on?" is counted by exactly
17
+ // the rule the block is split by — count and split disagreeing is how
18
+ // every header diagnostic in a DOS or classic-Mac file ends up one line
19
+ // off.
20
+ //
21
+ // Deliberately NOT the same set as `countLines` in composed-source.ts,
22
+ // which adds U+2028/U+2029 because V8 treats them as terminators. Those
23
+ // can't appear in a metadata line anyway (`TAG_LINE`'s `.` doesn't
24
+ // match them), and widening the split here would change what this
25
+ // long-standing parser considers a line.
26
+ const LINE_BREAK = /\r\n|\r|\n/;
27
+ const LINE_BREAK_G = /\r\n|\r|\n/g;
28
+ function countLineBreaks(text) {
29
+ return text.match(LINE_BREAK_G)?.length ?? 0;
30
+ }
31
+ // A marker line is `//`, optional spaces or tabs, then the marker, with
32
+ // anything before or after it on the line, as VM matches it. GreasyFork
33
+ // serves scripts opening with `/// ==UserScript==` or closing with
34
+ // `// ==/UserScript==////`, and TM and VM both install them. Each match
35
+ // takes the whole line, so text after a closing marker (part of that
36
+ // comment) stays in the header rather than starting the body.
37
+ //
38
+ // `[^\r\n]` and a lookbehind rather than `/m` with `.`, `^` and `$`:
39
+ // those also break at U+2028/U+2029, which `LINE_BREAK` deliberately
40
+ // doesn't treat as line breaks.
41
+ const BLOCK_START = /(?<![^\r\n])[^\r\n]*?\/\/[ \t]*==UserScript==[^\r\n]*/;
42
+ const BLOCK_END = /(?<![^\r\n])[^\r\n]*?\/\/[ \t]*==\/UserScript==[^\r\n]*/;
43
+ // Strip a single leading UTF-8 BOM. Most fetch paths (`response.text()`,
44
+ // `TextDecoder`) drop it for us, but the page-context `file://` XHR path
45
+ // (`directories.ts`) hands back `xhr.responseText` with the BOM intact.
46
+ // The marker regexes would take it as text before the `//` on line 1,
47
+ // leaving it in `headerText` (and GM_info's metadata string) rather than
48
+ // dropped. The BOM only ever appears at file position 0.
49
+ function stripLeadingBom(source) {
50
+ return source.charCodeAt(0) === 0xfeff ? source.slice(1) : source;
51
+ }
52
+ // The ways the split can fail, as the text a user reads.
53
+ //
54
+ // Named constants rather than inline literals because these strings are
55
+ // both the message and the value something compares against — today the
56
+ // corpus validator, which groups failures by message. A reworded
57
+ // literal would silently stop matching.
58
+ //
59
+ // Phrased to read correctly in all three places they appear: alone in
60
+ // the viewer's message bar, alone in the Log tab, and after the
61
+ // preview's `This file cannot be installed: ` prefix. Capitalized and
62
+ // unpunctuated per docs/diagnostics.md#wording; that still rules out a
63
+ // bare fragment like `No metadata block`, which needs a subject.
64
+ export const NO_METADATA_BLOCK = 'No // ==UserScript== metadata block, so this is not a userscript';
65
+ // The fix is phrased as a need rather than an instruction ("it needs",
66
+ // not "add"): this message carries a location, so it renders as
67
+ // `… — add a … line (in f.user.js, line 1)`, where the parenthetical
68
+ // reads as *where to add it*. Line 1 is where the block opened.
69
+ export const UNTERMINATED_METADATA_BLOCK = 'The // ==UserScript== metadata block is never closed and needs a // ==/UserScript== line';
70
+ // A file with no userscript block but a `/* ==UserStyle==` one is a
71
+ // user style (CSS for a style manager extension, not a userscript).
72
+ // GreasyFork lists them alongside userscripts, so naming what the file
73
+ // is beats calling it "not a userscript".
74
+ export const USERSTYLE_NOT_SUPPORTED = 'This is a user style (a /* ==UserStyle== block), not a userscript. User styles need a user style manager extension.';
75
+ const USERSTYLE_START = /\/\*[ \t]*==UserStyle==/;
76
+ // Split a userscript source into the (rare) text above the metadata
77
+ // block, the raw metadata block itself, and the body text.
78
+ //
79
+ // Failure modes:
80
+ // - no `==UserScript==` line → NO_METADATA_BLOCK, or
81
+ // USERSTYLE_NOT_SUPPORTED when there's a `/* ==UserStyle==` instead
82
+ // - open marker but no matching close → UNTERMINATED_METADATA_BLOCK
83
+ // In every case we return leadingText = '', headerText = '', and
84
+ // bodyText = the whole source so callers always have something to
85
+ // display.
86
+ export function splitHeaderBody(source) {
87
+ source = stripLeadingBom(source);
88
+ const startMatch = BLOCK_START.exec(source);
89
+ if (!startMatch) {
90
+ const error = USERSTYLE_START.test(source) ? USERSTYLE_NOT_SUPPORTED : NO_METADATA_BLOCK;
91
+ return { leadingText: '', headerText: '', bodyText: source, error };
92
+ }
93
+ const headerStartLine = countLineBreaks(source.slice(0, startMatch.index)) + 1;
94
+ const afterStart = source.slice(startMatch.index + startMatch[0].length);
95
+ const endMatch = BLOCK_END.exec(afterStart);
96
+ if (!endMatch) {
97
+ return {
98
+ leadingText: '',
99
+ headerText: '',
100
+ bodyText: source,
101
+ error: UNTERMINATED_METADATA_BLOCK,
102
+ headerStartLine,
103
+ };
104
+ }
105
+ const blockEnd = startMatch.index + startMatch[0].length + endMatch.index + endMatch[0].length;
106
+ // Skip a single trailing newline after the closing marker so bodyText
107
+ // doesn't start with a stray blank line.
108
+ let bodyStart = blockEnd;
109
+ if (source[bodyStart] === '\r')
110
+ bodyStart++;
111
+ if (source[bodyStart] === '\n')
112
+ bodyStart++;
113
+ return {
114
+ leadingText: source.slice(0, startMatch.index),
115
+ headerText: source.slice(startMatch.index, blockEnd),
116
+ bodyText: source.slice(bodyStart),
117
+ headerStartLine,
118
+ };
119
+ }
120
+ // One metadata line: `// @tag[:locale][ value]`. The value group is
121
+ // `.*\S` so trailing whitespace is excluded; the whole value group is
122
+ // optional so flag tags like `@noframes` parse with value = "".
123
+ const TAG_LINE = /^[ \t]*\/\/[ \t]*@([A-Za-z][\w-]*)(?::([\w-]+))?(?:[ \t]+(.*\S))?[ \t]*$/;
124
+ // Reassemble the original on-disk source from the three parts
125
+ // produced by `splitHeaderBody`. The reassembly is line-for-line
126
+ // faithful so that an error reported on injected line N also points
127
+ // at line N of this reconstructed string (which is what the viewer
128
+ // shows in the main tab).
129
+ //
130
+ // The `'\n'` between `headerText` and `bodyText` restores the line
131
+ // break `splitHeaderBody` skipped past the closing marker; with no
132
+ // metadata block, both `leadingText` and `headerText` are empty so
133
+ // the body is returned verbatim.
134
+ export function joinFullSource(leadingText, headerText, bodyText) {
135
+ if (!headerText)
136
+ return leadingText + bodyText;
137
+ return leadingText + headerText + '\n' + bodyText;
138
+ }
139
+ // Parse the metadata block. Returns null if there is no
140
+ // `==UserScript==` / `==/UserScript==` pair.
141
+ export function parseHeader(source) {
142
+ source = stripLeadingBom(source);
143
+ const startMatch = BLOCK_START.exec(source);
144
+ if (!startMatch)
145
+ return null;
146
+ const afterStart = source.slice(startMatch.index + startMatch[0].length);
147
+ const endMatch = BLOCK_END.exec(afterStart);
148
+ if (!endMatch)
149
+ return null;
150
+ const block = afterStart.slice(0, endMatch.index);
151
+ const startLine = countLineBreaks(source.slice(0, startMatch.index)) + 1;
152
+ const tags = [];
153
+ // Split on every line-terminator shape — `\r\n` (DOS), `\n` (Unix),
154
+ // and bare `\r` (classic Mac). `splitHeaderBody`'s marker regexes
155
+ // stop at all three too, so we keep parity here.
156
+ //
157
+ // `block` begins with the terminator that ended the `==UserScript==`
158
+ // line, so element 0 is always the empty remainder of that line and
159
+ // element i is `startLine + i` — no off-by-one correction needed.
160
+ for (const [i, rawLine] of block.split(LINE_BREAK).entries()) {
161
+ const m = TAG_LINE.exec(rawLine);
162
+ if (!m)
163
+ continue;
164
+ const [, tag, locale, value] = m;
165
+ const entry = {
166
+ tag: tag.toLowerCase(),
167
+ value: value ?? '',
168
+ line: startLine + i,
169
+ };
170
+ if (locale)
171
+ entry.locale = locale;
172
+ tags.push(entry);
173
+ }
174
+ return { tags, startLine };
175
+ }
176
+ // First non-localized value for `tag`, or undefined.
177
+ export function getValue(header, tag) {
178
+ const t = tag.toLowerCase();
179
+ for (const e of header.tags) {
180
+ if (e.tag === t && e.locale === undefined)
181
+ return e.value;
182
+ }
183
+ return undefined;
184
+ }
185
+ // All non-localized values for `tag`, in source order.
186
+ export function getValues(header, tag) {
187
+ const t = tag.toLowerCase();
188
+ const out = [];
189
+ for (const e of header.tags) {
190
+ if (e.tag === t && e.locale === undefined)
191
+ out.push(e.value);
192
+ }
193
+ return out;
194
+ }
195
+ // Map of locale → value for tags like `@name:de`. Excludes the
196
+ // unlocalized form.
197
+ export function getLocalized(header, tag) {
198
+ const t = tag.toLowerCase();
199
+ const out = {};
200
+ for (const e of header.tags) {
201
+ if (e.tag === t && e.locale !== undefined)
202
+ out[e.locale] = e.value;
203
+ }
204
+ return out;
205
+ }
206
+ // True if the tag appears at all (useful for flag-style tags like
207
+ // `@noframes` or `@unwrap`).
208
+ export function hasTag(header, tag) {
209
+ const t = tag.toLowerCase();
210
+ return header.tags.some((e) => e.tag === t);
211
+ }
212
+ // The `@run-at` values that pick a point in the page load. Anything
213
+ // else (a typo) runs at `document-idle`: see `normalizeDeclaredRunAt`
214
+ // in injector.ts. The exception is `context-menu`, which makes the
215
+ // script manual instead (see `CONTEXT_MENU_RUN_AT`).
216
+ export const SUPPORTED_RUN_AT = [
217
+ 'document-start',
218
+ 'document-body',
219
+ 'document-end',
220
+ 'document-idle',
221
+ ];
222
+ // The script's declared `@run-at` when it is one we don't honor, so
223
+ // the caller can say it runs at `document-idle` instead. Undefined when
224
+ // the tag is absent, blank, supported, or `context-menu`.
225
+ export function unsupportedRunAt(header) {
226
+ if (!header)
227
+ return undefined;
228
+ const value = (getValue(header, 'run-at') ?? '').trim();
229
+ if (value === '' || SUPPORTED_RUN_AT.includes(value.toLowerCase()))
230
+ return undefined;
231
+ if (value.toLowerCase() === CONTEXT_MENU_RUN_AT)
232
+ return undefined;
233
+ return value;
234
+ }
235
+ // Tampermonkey's `@run-at context-menu`: don't run on page load, run
236
+ // from a right-click menu item instead. We call these manual scripts:
237
+ // they match pages as usual, but run only when the person picks "Run
238
+ // this script" in the popup (or sm-dev fires it). See
239
+ // docs/manual-scripts.md.
240
+ export const CONTEXT_MENU_RUN_AT = 'context-menu';
241
+ // The command that runs a manual script now: first in its popup row,
242
+ // and in sm-dev's `menu`.
243
+ export const RUN_SCRIPT_LABEL = 'Run this script';
244
+ export function isContextMenuRunAt(header) {
245
+ if (!header)
246
+ return false;
247
+ return (getValue(header, 'run-at') ?? '').trim().toLowerCase() === CONTEXT_MENU_RUN_AT;
248
+ }