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,322 @@
1
+ // Pure display helpers for collections: type classification,
2
+ // display-name inference, and the colored type-bubble bookkeeping
3
+ // shared by the collections page and the userscript viewer.
4
+ //
5
+ // The bubble a collection wears says what KIND it is and, for a
6
+ // location-backed one, where it lives:
7
+ // - `scripts` : a container of individually installed
8
+ // scripts (may mix local, web, and GitHub)
9
+ // - `<scheme>-dir` : a scanned directory (`file-dir`, `github-dir`)
10
+ // - `<scheme>-manifest` : a `script_manifest.json` (`file-`, `http-`,
11
+ // `github-manifest`)
12
+ // where the scheme is a display-only label — it doesn't drive the
13
+ // scan/fetch dispatch (which lives in `directories.ts` and keys off URL
14
+ // shape and `isGithubDirCollection` / manifest detection):
15
+ // - github : github.com/* or raw.githubusercontent.com/*
16
+ // - http : any other http(s) URL
17
+ // - file : raw filesystem path or file:// URL
18
+ //
19
+ // Inside a `scripts` collection each row wears its own scheme chip
20
+ // (`makeSchemeChip`), since the collection itself has no single scheme.
21
+ // The light location modules, not directories.ts: the toolbar popup
22
+ // draws type bubbles and must not load the scanning and fetch code.
23
+ import { containerKind, containerPath, isContainerCollection, isFileUrl, isHttpUrl, pathToFileUrl, isManifestCollection, } from '../file-locations.js';
24
+ import { githubRawToBlobUrl } from '../github-urls.js';
25
+ import { isSmDevCollection, scriptSchemeKind } from './location-kinds.js';
26
+ import { MANIFEST_FILENAME } from '../collection-scan.js';
27
+ import { decodeForDisplay } from '../script-display.js';
28
+ // Why a script's enable checkbox is greyed out when its parent is off.
29
+ // Stands in for `ENABLE_TITLE` on every surface that draws one, so the
30
+ // collections page, the viewer's controls row, and the "Other versions"
31
+ // panel all explain it the same way.
32
+ export const COLLECTION_OFF_TITLE = 'Collection is disabled';
33
+ const GITHUB_HOST_RE = /^https?:\/\/(www\.)?github\.com\//i;
34
+ const RAW_GITHUB_HOST_RE = /^https?:\/\/raw\.githubusercontent\.com\//i;
35
+ // Display-only scheme classification of a collection's location.
36
+ // Stable across refreshes because it only depends on the collection
37
+ // path. GitHub recognition is intentionally broad — it covers both the
38
+ // canonical browse URL (`github.com/.../tree/...`) and the raw-content
39
+ // host (`raw.githubusercontent.com/...`) so any scheme of GitHub
40
+ // collection reads as `github` in the UI.
41
+ //
42
+ // A container has no location, so it falls through to `file` — which
43
+ // is the right answer for the one caller that asks about containers
44
+ // (`isLocalCollection` in refresh-targets: a container's local rows are
45
+ // refreshed one by one). Its bubble never comes from here.
46
+ export function inferCollectionType(path) {
47
+ if (GITHUB_HOST_RE.test(path) || RAW_GITHUB_HOST_RE.test(path))
48
+ return 'github';
49
+ if (isHttpUrl(path))
50
+ return 'http';
51
+ return 'file';
52
+ }
53
+ // Fixed human-readable titles for the three built-in default
54
+ // containers. These drive both the displayName backfill and the name
55
+ // the install page shows for a default that doesn't exist yet. The
56
+ // user can rename the row afterwards; the default is recognised by its
57
+ // path (`containerKind`), not by this text.
58
+ export const CONTAINER_DISPLAY_NAMES = {
59
+ file: 'Scripts from local disk',
60
+ http: 'Scripts from web',
61
+ github: 'Scripts from GitHub',
62
+ };
63
+ // The name for a container whose row carries no `displayName` — a
64
+ // pre-rename default, or (never, but defensively) a user-created one
65
+ // saved without a name. Never the raw `container:<uuid>` path.
66
+ export const UNNAMED_COLLECTION = 'Unnamed collection';
67
+ // Bubble label / CSS-key for a container: one word, since a container
68
+ // may hold scripts from every scheme.
69
+ export const SCRIPTS_BUBBLE_KEY = 'scripts';
70
+ // An sm-dev run's test collection: a scripts collection only its run
71
+ // changes.
72
+ export const SM_DEV_BUBBLE_KEY = 'sm-dev';
73
+ // The built-in default containers' names are reserved, whether or not
74
+ // the row exists yet. Without this a user could name their own
75
+ // collection "Scripts from web", and the first web install would then
76
+ // auto-create `container:http` under that same name — two entries in
77
+ // the install dropdown reading identically, in a state that could not
78
+ // be re-created afterwards (the rename would be refused as a
79
+ // duplicate). Returns the kind that owns the name, or null.
80
+ //
81
+ // The owning default itself is exempt: it already has the name, and
82
+ // re-saving its own name must not be refused.
83
+ export function reservedNameOwner(name) {
84
+ const key = name.trim().toLowerCase();
85
+ if (!key)
86
+ return null;
87
+ for (const [kind, label] of Object.entries(CONTAINER_DISPLAY_NAMES)) {
88
+ if (label.toLowerCase() === key)
89
+ return kind;
90
+ }
91
+ return null;
92
+ }
93
+ // Why a name can't be used: a built-in collection owns it. The name
94
+ // isn't repeated back — the user is standing at the field they just
95
+ // typed it into.
96
+ export const RESERVED_COLLECTION_NAME = 'Built-in collection name is reserved. Choose another name.';
97
+ // True when the given collection may carry a reserved name: it IS the
98
+ // default that owns it. `path` is the row being created or edited;
99
+ // pass null when creating a user collection, which never may.
100
+ export function mayUseReservedName(name, path) {
101
+ const owner = reservedNameOwner(name);
102
+ return owner === null || (path !== null && path === containerPath(owner));
103
+ }
104
+ // True when two collections would collide on name. Case-insensitive
105
+ // and whitespace-trimmed, since two names that differ only that way
106
+ // would read as one in the install dropdown. `excludeId` lets an edit
107
+ // keep its own current name.
108
+ export function collectionNameInUse(name, collections, excludeId) {
109
+ const key = name.trim().toLowerCase();
110
+ if (!key)
111
+ return false;
112
+ return collections.some((c) => c.id !== excludeId && effectiveDisplayName(c).trim().toLowerCase() === key);
113
+ }
114
+ // True for manifest collections of any scheme. Thin wrapper so callers
115
+ // don't have to import `directories` just for this. Container
116
+ // collections can never be manifests — their `path` is the synthetic
117
+ // `container:…` identifier.
118
+ export function collectionHasManifest(path) {
119
+ if (isContainerCollection(path))
120
+ return false;
121
+ return isManifestCollection(path);
122
+ }
123
+ // Bubble label / CSS-key for a collection: `scripts` for a container
124
+ // (`sm-dev` for an sm-dev run's test collection), `<scheme>-dir` for a
125
+ // scanned directory, `<scheme>-manifest` for a manifest. Same string
126
+ // powers the CSS class (`bubble-<key>`) and the visible text.
127
+ export function collectionBubbleKey(path) {
128
+ if (isSmDevCollection(path))
129
+ return SM_DEV_BUBBLE_KEY;
130
+ if (isContainerCollection(path))
131
+ return SCRIPTS_BUBBLE_KEY;
132
+ const t = inferCollectionType(path);
133
+ return collectionHasManifest(path) ? `${t}-manifest` : `${t}-dir`;
134
+ }
135
+ // The small per-row scheme chip a script wears inside a `scripts`
136
+ // collection — `file` / `http` / `github` / `scratch` — since the collection's own
137
+ // bubble can't say where each of its scripts loads from. Classified
138
+ // from the script's own location (`relativePath` in a container is the
139
+ // full URL/path the user installed).
140
+ export function makeSchemeChip(location) {
141
+ const scheme = scriptSchemeKind(location);
142
+ const span = document.createElement('span');
143
+ span.className = `scheme-chip chip-${scheme}`;
144
+ span.textContent = scheme;
145
+ span.title = {
146
+ file: 'Loaded from a local file',
147
+ http: 'Loaded from the web',
148
+ github: 'Loaded from GitHub',
149
+ scratch: 'Stored only in SourceMonkey',
150
+ }[scheme];
151
+ return span;
152
+ }
153
+ // Openable URL for a collection — the link target the bubble uses. For
154
+ // github raw URLs (manifest collections, post-add-time normalization)
155
+ // we return the `github.com/.../blob/...` page URL instead, since the
156
+ // bubble exists for humans to click — the raw bytes are only used
157
+ // internally for fetching. All other http(s) / file:// URLs pass
158
+ // through; raw filesystem paths become file:// URLs so the anchor has a
159
+ // valid href (Chromium typically refuses to navigate to file:// from a
160
+ // chrome-extension page, but the URL is still readable + copyable).
161
+ // Container collections have no underlying URL — return null and let
162
+ // callers render the bubble as a non-link.
163
+ export function collectionClickUrl(path) {
164
+ if (isContainerCollection(path))
165
+ return null;
166
+ if (isHttpUrl(path)) {
167
+ return githubRawToBlobUrl(path) ?? path;
168
+ }
169
+ if (isFileUrl(path))
170
+ return path;
171
+ return pathToFileUrl(path);
172
+ }
173
+ // Derive a short, human-readable display name from a collection path. The
174
+ // rules trim noise from the beginning, middle, and end of the link:
175
+ // - drop the protocol prefix (https://, http://, file://)
176
+ // - drop any `?query` tail
177
+ // - drop a trailing `/<MANIFEST_FILENAME>` so a manifest collection reads
178
+ // as the directory that hosts it
179
+ // - github.com / raw.githubusercontent.com get scheme-specific
180
+ // simplifications so the common shapes read as `<owner>/<repo>`
181
+ // or `<owner>/<repo>/<ref>/<path>` rather than the full URL
182
+ // - trailing slashes are stripped
183
+ //
184
+ // The result is stable across refreshes (depends only on the path),
185
+ // short enough for the collections-page heading, and a reasonable seed for
186
+ // a future user-renamed displayName.
187
+ export function inferDisplayName(path) {
188
+ const ck = containerKind(path);
189
+ if (ck)
190
+ return CONTAINER_DISPLAY_NAMES[ck];
191
+ // A user-created container has no location to infer from; its name
192
+ // is whatever the user typed, stored in `displayName`.
193
+ if (isContainerCollection(path))
194
+ return '';
195
+ let s = path.trim();
196
+ // Strip the fragment + query first so trailing noise can't leak into
197
+ // any downstream substitution (e.g. `?token=...` on a manifest URL,
198
+ // or `#install-section` on a GreasyFork link).
199
+ const h = s.indexOf('#');
200
+ if (h >= 0)
201
+ s = s.slice(0, h);
202
+ const q = s.indexOf('?');
203
+ if (q >= 0)
204
+ s = s.slice(0, q);
205
+ // Strip the protocol prefix uniformly. Raw fs paths have none and
206
+ // pass through; file:// URLs become bare absolute paths, which is
207
+ // what users typically recognise.
208
+ s = s.replace(/^https?:\/\//i, '').replace(/^file:\/\//i, '');
209
+ // Drop a trailing manifest filename so `…/foo/script_manifest.json`
210
+ // reads as `…/foo`.
211
+ if (s.endsWith('/' + MANIFEST_FILENAME)) {
212
+ s = s.slice(0, -(MANIFEST_FILENAME.length + 1));
213
+ }
214
+ // GitHub-specific simplifications. Each rule has its own anchor on
215
+ // the URL shape; early-return after the first match so a literal
216
+ // directory named `tree` or `blob` (post-rewrite) doesn't get
217
+ // re-consumed by a later rule. Order doesn't matter once we exit
218
+ // after the first hit. Longer literal segments listed first only as
219
+ // a readability hint.
220
+ if (/^(www\.)?github\.com\//i.test(s)) {
221
+ s = s.replace(/^(www\.)?github\.com\//i, '');
222
+ s = applyFirstGithubRule(s);
223
+ }
224
+ else if (/^raw\.githubusercontent\.com\//i.test(s)) {
225
+ s = s.replace(/^raw\.githubusercontent\.com\//i, '');
226
+ // New-style raw URLs carry an extra `/refs/heads/` segment before
227
+ // the branch name; strip it so the form mirrors the legacy shape.
228
+ const m = /^([^\/]+\/[^\/]+)\/refs\/heads\/([^\/]+)(\/.*)?$/.exec(s);
229
+ if (m)
230
+ s = `${m[1]}/${m[2]}${m[3] ?? ''}`;
231
+ }
232
+ // Trim trailing slashes so e.g. `…/dir/` reads as `…/dir`.
233
+ s = s.replace(/\/+$/, '');
234
+ // Decode percent-encoded characters so e.g. a GreasyFork URL with
235
+ // `OnePelotoncom%20Cycle...` reads as `OnePelotoncom Cycle...`.
236
+ // Same decode-for-display rule the rest of the UI follows — see
237
+ // docs/names-and-paths.md.
238
+ return decodeForDisplay(s);
239
+ }
240
+ // Try each github URL-shape rewrite in turn and return on the first
241
+ // hit. Single-pass match avoids the chain-rewrite hazard where a
242
+ // post-rewrite path that happens to contain a literal `blob` / `tree`
243
+ // directory would be re-interpreted by a later rule.
244
+ function applyFirstGithubRule(s) {
245
+ // `<owner>/<repo>/tree/<ref>(/<path>?)` → `<owner>/<repo>(/<path>?)`
246
+ let m = /^([^\/]+\/[^\/]+)\/tree\/[^\/]+(\/.*)?$/.exec(s);
247
+ if (m)
248
+ return m[1] + (m[2] ?? '');
249
+ // `<owner>/<repo>/blob/<ref>/<path>` → `<owner>/<repo>/<ref>/<path>`
250
+ m = /^([^\/]+\/[^\/]+)\/blob\/([^\/]+)(\/.*)?$/.exec(s);
251
+ if (m)
252
+ return `${m[1]}/${m[2]}${m[3] ?? ''}`;
253
+ // `<owner>/<repo>/raw/refs/heads/<branch>/<path>` →
254
+ // `<owner>/<repo>/<branch>/<path>`
255
+ m = /^([^\/]+\/[^\/]+)\/raw\/refs\/heads\/([^\/]+)(\/.*)?$/.exec(s);
256
+ if (m)
257
+ return `${m[1]}/${m[2]}${m[3] ?? ''}`;
258
+ // `<owner>/<repo>/raw/<ref>/<path>` → `<owner>/<repo>/<ref>/<path>`
259
+ m = /^([^\/]+\/[^\/]+)\/raw\/([^\/]+)(\/.*)?$/.exec(s);
260
+ if (m)
261
+ return `${m[1]}/${m[2]}${m[3] ?? ''}`;
262
+ return s;
263
+ }
264
+ // Canonical collections-page anchor for a collection. Lives here (not
265
+ // in collections.ts) so the viewer can link back to the right `#…`
266
+ // without reaching across pages for the helper.
267
+ export function collectionAnchorId(collectionId) {
268
+ return `collection-${collectionId}`;
269
+ }
270
+ // A collections-page fragment that opens a collection's edit dialog
271
+ // (the popup's "Collection options"): this prefix + the collection id.
272
+ export const EDIT_COLLECTION_HASH_PREFIX = 'edit-collection-';
273
+ // Construct the colored type-bubble for a collection. Shared by the
274
+ // collections page (heading) and the userscript viewer (Collection row)
275
+ // so the markup, classes, tooltip, and anchor target all stay in
276
+ // lockstep across both views. Returns an `<a>` for collections backed
277
+ // by a real URL/path, and a `<span>` for container collections (which
278
+ // have no underlying URL to link to).
279
+ export function makeCollectionTypeBubble(path) {
280
+ const key = collectionBubbleKey(path);
281
+ const href = collectionClickUrl(path);
282
+ if (href === null) {
283
+ // No URL to link to, so the tooltip says what this collection IS
284
+ // rather than naming the internal "container" kind — the user never
285
+ // sees that word — and why there is nothing to open: its scripts
286
+ // were installed one at a time and share no parent.
287
+ const span = document.createElement('span');
288
+ span.className = `collection-type-bubble bubble-${key}`;
289
+ span.textContent = key;
290
+ span.title = key === SM_DEV_BUBBLE_KEY
291
+ ? 'Scripts an sm-dev run pushed, which only that run changes'
292
+ : 'Collection of individual scripts (no common parent directory)';
293
+ return span;
294
+ }
295
+ const a = document.createElement('a');
296
+ a.className = `collection-type-bubble bubble-${key}`;
297
+ a.textContent = key;
298
+ a.href = href;
299
+ a.target = '_blank';
300
+ a.rel = 'noopener noreferrer';
301
+ // Names what clicking does, which differs by kind: a directory (local
302
+ // or a GitHub tree) opens somewhere you can look around; a manifest
303
+ // opens the one file that lists the scripts.
304
+ a.title = collectionHasManifest(path)
305
+ ? `Open manifest: ${path}`
306
+ : `Browse directory: ${path}`;
307
+ return a;
308
+ }
309
+ // Resolve the display name for a stored collection. Prefers the stored
310
+ // `displayName` (the user's own, or the one seeded at add time);
311
+ // otherwise falls back to the inferred one. The very last fallback is
312
+ // the raw `path` — or a placeholder for a container, whose synthetic
313
+ // path is not for showing — so the UI never renders an empty string.
314
+ export function effectiveDisplayName(collection) {
315
+ const stored = collection.displayName?.trim();
316
+ if (stored)
317
+ return stored;
318
+ const inferred = inferDisplayName(collection.path);
319
+ if (inferred)
320
+ return inferred;
321
+ return isContainerCollection(collection.path) ? UNNAMED_COLLECTION : collection.path;
322
+ }