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,358 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>SourceMonkey | Compare</title>
6
+ <link rel="stylesheet" href="styles.css" />
7
+ <style>
8
+ html { height: 100%; margin: 0; }
9
+ body {
10
+ min-height: 100%;
11
+ margin: 0;
12
+ font: 14px system-ui, sans-serif;
13
+ color: #222;
14
+ display: flex;
15
+ flex-direction: column;
16
+ box-sizing: border-box;
17
+ }
18
+ /* Same full-bleed column as the viewer: the header bar and the
19
+ page share a 16px inset and nothing else constrains the width —
20
+ two files side by side want all of it. */
21
+ .page-main {
22
+ flex: 1 1 auto;
23
+ min-height: 0;
24
+ display: flex;
25
+ flex-direction: column;
26
+ padding: 16px;
27
+ box-sizing: border-box;
28
+ }
29
+ h1 { overflow-wrap: anywhere; word-break: normal; }
30
+ .message { margin: 0 0 11px; }
31
+ .message:empty { display: none; }
32
+ .message.error { color: #b00020; }
33
+
34
+ /* ---- The fields table: Field | one side | swap | other side ---- */
35
+ /* The viewer's details card, with a third column. */
36
+ #fields {
37
+ margin: 0 0 11px;
38
+ padding: 8px 11px;
39
+ border: 1px solid #ddd;
40
+ border-radius: 4px;
41
+ background: #f5f7fa;
42
+ }
43
+ #fields:empty { display: none; }
44
+ table.fields { border-collapse: collapse; width: 100%; }
45
+ table.fields th,
46
+ table.fields td {
47
+ text-align: left;
48
+ vertical-align: top;
49
+ padding: 0.15em 0.8em 0.15em 0;
50
+ }
51
+ table.fields th { font-weight: 600; color: #555; white-space: nowrap; }
52
+ /* The head is the two rows that tell the copies apart — the
53
+ collection, in the heading's weight, and the location under it
54
+ — ruled off from the fields below. */
55
+ table.fields thead tr.side-collection td { font-weight: 600; }
56
+ table.fields thead tr.side-location td { font-size: 12.5px; color: #555; }
57
+ /* When the two differ these rows take only the background tint:
58
+ the collection name and the path stay in their own colours,
59
+ readable beside the bubble, which keeps its own too. */
60
+ table.fields thead tr.side-collection.differs td.value { color: #222; }
61
+ table.fields thead tr.side-location.differs td.value { color: #555; }
62
+ table.fields thead tr.side-location th,
63
+ table.fields thead tr.side-location td { padding-bottom: 6px; border-bottom: 1px solid #d5dae2; }
64
+ table.fields tbody tr:first-child th,
65
+ table.fields tbody tr:first-child td { padding-top: 6px; }
66
+ /* The "not installed" side of a preview comparison. */
67
+ .side-preview { font-style: italic; color: #555; }
68
+ /* Both value columns take the same share; the swap column is as
69
+ narrow as its button. */
70
+ table.fields td.value { width: 45%; overflow-wrap: anywhere; word-break: normal; }
71
+ table.fields .swap-col { width: 1px; padding: 0 0.5em; text-align: center; vertical-align: middle; }
72
+ /* A row whose two values differ wears the diff's own colours, so
73
+ the table reads as the diff of the header. */
74
+ tr.differs td.value.left { background: var(--diff-del-bg); color: var(--diff-del-fg); }
75
+ tr.differs td.value.right { background: var(--diff-add-bg); color: var(--diff-add-fg); }
76
+ /* A list value: one item per line, and an item the other side
77
+ lacks is what carries the row's tint. */
78
+ table.fields ul { margin: 0; padding-left: 1.1em; }
79
+ tr.differs td.value.left li.only { background: #f7c4c4; }
80
+ tr.differs td.value.right li.only { background: #bfe8c9; }
81
+ /* A field one side declares and the other does not. */
82
+ .none { color: #999; }
83
+ /* The collection's bubble and name, as the viewer's Collection
84
+ row draws them (`collectionCell`, script-details.ts). */
85
+ .collection-cell { display: inline-flex; align-items: baseline; gap: 0.5em; min-width: 0; }
86
+ /* Not the type bubble: it is a link too, and keeps its own white
87
+ text on its own colour, tinted row or not. */
88
+ .collection-cell a:not(.collection-type-bubble),
89
+ tr.side-location a { color: inherit; text-decoration: none; }
90
+ .collection-cell a:not(.collection-type-bubble):hover,
91
+ tr.side-location a:hover { text-decoration: underline; }
92
+
93
+ /* ---- View controls, right-aligned on their own row above the tabs ---- */
94
+ .view-row {
95
+ display: flex;
96
+ justify-content: flex-end;
97
+ align-items: center;
98
+ gap: 0.8em;
99
+ margin: 0 0 6px;
100
+ font-size: 12.5px;
101
+ color: #555;
102
+ }
103
+ .view-row:empty { display: none; }
104
+ /* A segmented control: the shared button surface (styles.css),
105
+ the segments joined edge to edge, and the chosen one held
106
+ down — pressed darker, sunk with an inset shadow — so which
107
+ state is in force reads as the button that stays pushed. */
108
+ .seg { display: inline-flex; }
109
+ .seg button {
110
+ font-size: 12.5px;
111
+ padding: 0 10px;
112
+ border-radius: 0;
113
+ }
114
+ .seg button:first-child { border-radius: 3px 0 0 3px; }
115
+ .seg button:last-child { border-radius: 0 3px 3px 0; }
116
+ .seg button + button { margin-left: -1px; }
117
+ .seg button.on {
118
+ background: var(--btn-bg-active);
119
+ border-color: #999;
120
+ box-shadow: inset 0 2px 3px rgba(0, 0, 0, 0.2);
121
+ font-weight: 600;
122
+ /* The pressed one stays on top so its darker border shows on
123
+ both sides where the segments overlap. */
124
+ position: relative;
125
+ z-index: 1;
126
+ }
127
+
128
+ /* ---- Tabs: one per file, each with its verdict chip ---- */
129
+ /* The strip itself is shared with the viewer (styles.css). */
130
+ .tab .chip {
131
+ margin-left: 0.6em;
132
+ padding: 0 0.4em;
133
+ border-radius: 3px;
134
+ font-family: system-ui, sans-serif;
135
+ font-size: 10px;
136
+ font-weight: 600;
137
+ letter-spacing: 0.04em;
138
+ text-transform: uppercase;
139
+ color: #fff;
140
+ vertical-align: 1px;
141
+ }
142
+ /* The versions panel's SAME green and DIFFERENT blue; amber for a
143
+ file only one side has, the colour of "not the same thing"
144
+ elsewhere on these pages. */
145
+ .chip-same { background: #166534; }
146
+ .chip-different { background: var(--chip-different); }
147
+ .chip-added, .chip-removed { background: #b67200; }
148
+
149
+ /* ---- The diff box ---- */
150
+ :root {
151
+ --chip-different: #1d4ed8;
152
+ --diff-del-bg: #fde8e8;
153
+ --diff-del-fg: #8a1c1c;
154
+ --diff-add-bg: #e3f6e8;
155
+ --diff-add-fg: #14532d;
156
+ }
157
+ /* The box fills what is left of the window and the lines scroll
158
+ inside it, as the viewer's code box does: that puts the scroll
159
+ bars at the window's edge, where they can be reached, rather
160
+ than under a page's worth of code. Basis 0 so its content never
161
+ sizes the page; the floor below keeps a useful number of lines
162
+ in view under a tall fields table, letting the PAGE scroll then
163
+ — the one case this page accepts a page-level scroll bar.
164
+ 20 lines at this box's line height, plus the summary strip and
165
+ the border. Meets the active tab the way the viewer's box does. */
166
+ .page-main { --code-box-min: calc(20 * 1.5 * 13px + 30px + 2px); }
167
+ .diff-box {
168
+ flex: 1 1 0;
169
+ min-height: var(--code-box-min);
170
+ display: flex;
171
+ flex-direction: column;
172
+ box-sizing: border-box;
173
+ margin-top: -1px;
174
+ border: 1px solid #ccc;
175
+ border-radius: 0 4px 4px 4px;
176
+ background: #fafafa;
177
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
178
+ font-size: 13px;
179
+ line-height: 1.5;
180
+ overflow: hidden;
181
+ }
182
+ .diff-box[hidden] { display: none; }
183
+ .diff-body { flex: 1 1 auto; min-height: 0; overflow: auto; }
184
+ .diff-body:focus, .diff-body .pane:focus { outline: 2px solid #4a90e2; outline-offset: -2px; }
185
+ /* Side by side: two panes, each its own scroller, split down the
186
+ middle so both are always in view. */
187
+ .diff-body.split { display: flex; overflow: hidden; }
188
+ /* Sideways scroll bars always, in both: one pane with a bar and
189
+ one without would have different heights to scroll, and the
190
+ linked scroll would hit the end in one before the other. */
191
+ .diff-body.split .pane { flex: 1 1 50%; min-width: 0; overflow: auto; overflow-x: scroll; }
192
+ .diff-body.split .pane.right { border-left: 1px solid #ccc; }
193
+ /* The one line of summary: the counts, right-aligned, then the
194
+ Up/Down arrows that jump between change blocks. The arrows are
195
+ icon buttons shrunk to the strip's line (the two custom
196
+ properties, styles.css), and the strip is held at their
197
+ height whether or not it has them (`No differences` has
198
+ none), so the lines do not shift between tabs. That height
199
+ is within the 30px the box's floor (`--code-box-min`, above)
200
+ reserves for the strip. */
201
+ .diff-summary {
202
+ --icon-btn-size: 20px;
203
+ --icon-btn-glyph: 14px;
204
+ min-height: 20px;
205
+ flex: 0 0 auto;
206
+ display: flex;
207
+ justify-content: flex-end;
208
+ align-items: center;
209
+ gap: 0.4em;
210
+ padding: 4px 12px;
211
+ border-bottom: 1px solid #e3e3e3;
212
+ background: #f3f4f6;
213
+ font-family: system-ui, sans-serif;
214
+ font-size: 12.5px;
215
+ color: #555;
216
+ }
217
+ .diff-summary .diff-counts { margin-right: 0.6em; }
218
+ .diff-summary .removed { color: var(--diff-del-fg); font-weight: 600; }
219
+ .diff-summary .added { color: var(--diff-add-fg); font-weight: 600; }
220
+ table.diff { border-collapse: collapse; width: 100%; }
221
+ table.diff td { padding: 0 8px; white-space: pre; vertical-align: top; }
222
+ /* Line-number gutters: fixed, dim, not selectable, so copying a
223
+ run of lines copies the code. */
224
+ table.diff td.num {
225
+ width: 3ch;
226
+ min-width: 3ch;
227
+ text-align: right;
228
+ color: #999;
229
+ user-select: none;
230
+ padding-right: 4px;
231
+ border-right: 1px solid #e5e5e5;
232
+ }
233
+ table.diff td.sign { width: 1ch; color: #888; user-select: none; text-align: center; padding: 0 2px; }
234
+ table.diff tr.del td { background: var(--diff-del-bg); }
235
+ table.diff tr.del td.code { color: var(--diff-del-fg); }
236
+ table.diff tr.add td { background: var(--diff-add-bg); }
237
+ table.diff tr.add td.code { color: var(--diff-add-fg); }
238
+ table.diff tr.del td.num, table.diff tr.add td.num { color: inherit; opacity: 0.6; }
239
+ /* The block the arrows last jumped to: its line numbers in the
240
+ DIFFERENT chip's blue, with a bar down the gutter's edge, on
241
+ each of its rows (the blanks across from it too, side by
242
+ side). In the gutter and not on the lines, so the change's
243
+ own colours are what the block shows. An inset shadow rather
244
+ than a border: nothing moves. Same specificity as the del/add
245
+ gutter rule above, so this one has to come after it. */
246
+ table.diff tr.current td.num {
247
+ color: var(--chip-different);
248
+ opacity: 1;
249
+ font-weight: 600;
250
+ box-shadow: inset 3px 0 0 var(--chip-different);
251
+ }
252
+ /* `@@ -a,n +b,m @@`: the seam between two hunks. */
253
+ table.diff tr.hunk td { background: #eef2f7; color: #4b5563; font-size: 12px; padding: 2px 8px; }
254
+ /* A pane's blank across from a line only the other side has. Its
255
+ cells are all empty, and a row of empty cells has no height —
256
+ which would put the two panes' rows out of step by exactly the
257
+ lines one side lacks. The no-break space gives it a line. */
258
+ table.diff tr.filler td { background: #f3f3f3; }
259
+ table.diff tr.filler td.code::after { content: "\00a0"; }
260
+ </style>
261
+ </head>
262
+ <body>
263
+ <!-- Shared glyph sprite: the one copy of every inline SVG glyph in the
264
+ extension. scripts/build.mjs inlines it into each page wherever the
265
+ page writes an `#include glyph-sprite` marker comment. (Spelling
266
+ that marker out here would be nice, but its own closing `--` plus
267
+ `>` would end THIS comment and spill the rest onto the page.)
268
+
269
+ One source of truth: the markup used to be copy-pasted into each
270
+ page's HTML, which is how two pages end up with glyphs that have
271
+ quietly drifted apart.
272
+
273
+ Each symbol is defined once per page and referenced by a `use`
274
+ element, so a hundred rows share one copy of the path data instead
275
+ of inlining it per row.
276
+
277
+ #sm-globe favicon placeholder until a site icon loads, and
278
+ the permanent icon for a script with no resolvable
279
+ origin (src/extension/site-icon.ts; styling on
280
+ `.site-icon-globe`).
281
+ #sm-trash remove SourceMonkey's record of a script.
282
+ #sm-trash-file delete the script FILE from disk — the same can,
283
+ badged with a disk. Both painted by
284
+ src/extension/delete-icon.ts, which explains the pair.
285
+ The can is drawn ~19% smaller than #sm-trash — its
286
+ own inner scale(.9) inside the normalizing
287
+ wrapper's scale(.9) — so the badge has a corner to
288
+ sit in without swallowing the can. Deliberate: the two appear in the same
289
+ column in the "Other versions" panel, and the
290
+ badged one has to stay a can at 15px.
291
+ #sm-copy the viewer's "copy this to the clipboard" button,
292
+ #sm-check and the checkmark it flashes on success
293
+ (src/extension/copy-button.ts).
294
+ #sm-refresh refetch a collection, a script, or one row of the
295
+ "Other versions" table. Its busy state is this
296
+ same arc spinning (`.btn-glyph.spinning`), so the
297
+ button never changes shape mid-refresh.
298
+ #sm-gear open a collection's rename / options dialog.
299
+ #sm-open open a location in a new tab (the collection
300
+ dialog's button beside its location box).
301
+ #sm-swap the compare page's "swap the two sides" button:
302
+ two arrows, one each way, the same width so their
303
+ ends line up.
304
+
305
+ Colour comes from `currentColor`, so a button's own `color` (and
306
+ its hover) drives the glyph.
307
+
308
+ OPTICAL SIZING — read before editing a path or a stroke width.
309
+ Identical 16px boxes do not make icons look the same size; the ink
310
+ inside them has to match too. As drawn, these ranged from 18 to
311
+ 23.3 units of 24, and the gear read ~22% larger than the arrow. So
312
+ a glyph that needed resizing is wrapped in
313
+ <g transform="translate(12 12) scale(k) translate(-12 -12)">
314
+ and its `stroke-width` is DIVIDED by the same k. Consequences:
315
+ - The number in the file is not the number that renders. Every
316
+ glyph here strokes at 1.75 units once its wrapper is applied
317
+ (1.9/... , 1.95/.9, 1.667*1.05, 1.825*.959). Change a stroke
318
+ width and you break that unless you change k with it.
319
+ - #sm-refresh translates by -13, not -12: Feather's rotate-cw is
320
+ drawn a unit right of centre, and this puts it back. It is not
321
+ a typo.
322
+ - #sm-copy and #sm-check are deliberately outside this: they
323
+ stroke at 2.0 in the 14px copy button. That button sits beside
324
+ the 1.75 set only in the collection dialog, next to #sm-open,
325
+ where the smaller box evens out the heavier stroke. -->
326
+ <svg width="0" height="0" style="position:absolute" aria-hidden="true">
327
+ <symbol id="sm-globe" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"></circle><path d="M2 12h20"></path><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path></symbol>
328
+ <symbol id="sm-trash" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 6h17"></path><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"></path><path d="M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2"></path><path d="M10 10.5v7"></path><path d="M14 10.5v7"></path></symbol>
329
+ <symbol id="sm-trash-file" viewBox="0 0 24 24"><g transform="translate(12 12) scale(.9) translate(-12 -12)"><mask id="sm-trash-file-cut" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24"><rect width="24" height="24" fill="#fff"></rect><circle cx="19.6" cy="19.6" r="5.2" fill="#000"></circle></mask><g mask="url(#sm-trash-file-cut)" transform="translate(-.7 -1.5) scale(.9)" fill="none" stroke="currentColor" stroke-width="2.167" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 6h17"></path><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"></path><path d="M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2"></path><path d="M10 10.5v7"></path><path d="M14 10.5v7"></path></g><g transform="translate(14.53 14.36) scale(.422)" fill="none" stroke="currentColor" stroke-width="4.611" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"></ellipse><path d="M3 5v14c0 1.66 4.03 3 9 3s9-1.34 9-3V5"></path></g></g></symbol>
330
+ <symbol id="sm-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></symbol>
331
+ <symbol id="sm-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></symbol>
332
+ <symbol id="sm-refresh" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.667" stroke-linecap="round" stroke-linejoin="round"><g transform="translate(12 12) scale(1.05) translate(-13 -12)"><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path><polyline points="23 4 23 10 17 10"></polyline></g></symbol>
333
+ <symbol id="sm-swap" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7.5h18"></path><path d="M16.5 3l4.5 4.5-4.5 4.5"></path><path d="M21 16.5H3"></path><path d="M7.5 12L3 16.5 7.5 21"></path></symbol>
334
+ <symbol id="sm-gear" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.825" stroke-linecap="round" stroke-linejoin="round"><g transform="translate(12 12) scale(.959) translate(-12 -12)"><circle cx="12" cy="12" r="3.1"></circle><path d="M19.4 14.6a1.6 1.6 0 0 0 .32 1.77l.06.06a1.95 1.95 0 1 1-2.76 2.76l-.06-.06a1.6 1.6 0 0 0-1.77-.32 1.6 1.6 0 0 0-.97 1.47V21a1.95 1.95 0 1 1-3.9 0v-.1a1.6 1.6 0 0 0-1.05-1.47 1.6 1.6 0 0 0-1.77.32l-.06.06a1.95 1.95 0 1 1-2.76-2.76l.06-.06a1.6 1.6 0 0 0 .32-1.77 1.6 1.6 0 0 0-1.47-.97H3a1.95 1.95 0 1 1 0-3.9h.1a1.6 1.6 0 0 0 1.47-1.05 1.6 1.6 0 0 0-.32-1.77l-.06-.06a1.95 1.95 0 1 1 2.76-2.76l.06.06a1.6 1.6 0 0 0 1.77.32H9a1.6 1.6 0 0 0 .97-1.47V3a1.95 1.95 0 1 1 3.9 0v.1a1.6 1.6 0 0 0 .97 1.47 1.6 1.6 0 0 0 1.77-.32l.06-.06a1.95 1.95 0 1 1 2.76 2.76l-.06.06a1.6 1.6 0 0 0-.32 1.77V9a1.6 1.6 0 0 0 1.47.97H21a1.95 1.95 0 1 1 0 3.9h-.1a1.6 1.6 0 0 0-1.47.97z"></path></g></symbol>
335
+ <symbol id="sm-open" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><path d="M10 14L21 3"></path></symbol>
336
+ </svg>
337
+ <header class="page-header">
338
+ <div class="page-header-inner">
339
+ <a class="page-home page-icon-link" href="collections.html" target="_blank"
340
+ rel="noopener" tabindex="-1" aria-hidden="true">
341
+ <img class="page-icon" src="icons/icon-48.png" alt="" />
342
+ </a>
343
+ <!-- The same brand run the viewer ships in its markup, so the bar
344
+ reads "SourceMonkey | Compare |" from the first paint. -->
345
+ <h1 id="heading"><a class="heading-prefix brand page-home" href="collections.html"
346
+ target="_blank" rel="noopener" title="Open the collections page">SourceMonkey</a><span class="heading-prefix brand"> | </span><span class="heading-prefix">Compare</span><span class="heading-prefix brand"> | </span></h1>
347
+ </div>
348
+ </header>
349
+ <div class="page-main">
350
+ <p id="message" class="message"></p>
351
+ <div id="fields"></div>
352
+ <div id="view-row" class="view-row"></div>
353
+ <div id="tabs" class="tabs" role="tablist" hidden></div>
354
+ <div id="diff" class="diff-box" hidden></div>
355
+ </div>
356
+ <script src="extension/compare.js" type="module"></script>
357
+ </body>
358
+ </html>
@@ -0,0 +1,205 @@
1
+ // ---------- Concatenated user source (requires + body) ----------
2
+ //
3
+ // Every prefetched `@require` body, in declaration order, in front of
4
+ // the **full on-disk script source** (leadingText + headerText +
5
+ // bodyText). This is the single arrangement every run path uses:
6
+ //
7
+ // - the default registration (`wrapCombinedEntry` → one js[] entry);
8
+ // - the reload-fast-path swap eval (`buildSwapEvalBody`), where
9
+ // `handleCheckPending` in background.ts sends the same text as the
10
+ // run-new body.
11
+ //
12
+ // Concatenation IS the feature, not an implementation detail: one
13
+ // script means one lexical scope, so a library's top-level
14
+ // `const`/`let`/`class` is simply visible to the main body — the same
15
+ // thing TM/VM get by concatenating into one IIFE. See
16
+ // docs/injection-modes.md for what the separate-entries arrangement
17
+ // cost us instead.
18
+ //
19
+ // A `;\n` separator between segments guards the seam against ASI
20
+ // (Automatic Semicolon Insertion). ASI won't fire when the next line
21
+ // could continue the previous statement, so a library ending in an
22
+ // expression followed by a body opening with `(`, `[`, `` ` ``, `+`,
23
+ // `-` or `/` would parse as a single statement. Each file was fine on
24
+ // its own; concatenation is what creates the hazard.
25
+ //
26
+ // The leading `// @require <url>` per require makes the concatenated
27
+ // code easier to scan when no source map is applied. Line comment (not
28
+ // block) so URLs with `*/` in their path don't prematurely close it.
29
+ //
30
+ // ---------- Why this lives in its own module ----------
31
+ //
32
+ // Several callers need to agree on the layout, and they live in
33
+ // different extension contexts:
34
+ //
35
+ // - `src/extension/injector.ts` (service worker) emits the registered entry
36
+ // and its source map.
37
+ // - `background.ts`'s swap path emits the same text for `(0,eval)`.
38
+ // - `src/extension/userscript.ts` (the viewer page) re-derives the SAME
39
+ // segment list to map `Error.stack` line numbers in the Log tab
40
+ // back to the original file — V8 leaves `err.stack` in generated
41
+ // coordinates even when it has the map. See docs/script-log.md.
42
+ //
43
+ // The viewer recomputes rather than reading a persisted map because
44
+ // the inputs are already on the `StoredScript` row it has loaded, and
45
+ // a persisted copy would be one more thing to invalidate. Sharing this
46
+ // one function is what keeps "where line N came from" a single answer
47
+ // instead of two that can drift.
48
+ import { joinFullSource } from './userscript-header.js';
49
+ import { buildRequireSourceUrl, buildSourceUrl } from './script-source-url.js';
50
+ // ---------- The two layouts, and why the viewer can tell them apart ----------
51
+ //
52
+ // **With `@require`s.** The preamble (GM bindings, prelude, wrap head)
53
+ // occupies generated line 0 on its own and the concatenated user
54
+ // source starts at `USER_SOURCE_START_LINE`. Line numbers shift, so
55
+ // the entry carries a source map and the viewer remaps stack refs
56
+ // through the segment list.
57
+ //
58
+ // **Without `@require`s.** Nothing is concatenated, so nothing may
59
+ // shift: the body's first line SHARES generated line 0 with the
60
+ // preamble, making generated line N equal original line N. No map is
61
+ // emitted and the viewer passes refs through untouched.
62
+ //
63
+ // The viewer distinguishes the two by whether there are segments at
64
+ // all — `composeSource` returns none for a script without requires —
65
+ // so it never has to know which run path produced the code. That only
66
+ // holds while `wrapCombinedEntry` and `buildSwapEvalBody` agree on
67
+ // BOTH layouts. They are the only two producers; keep them in step.
68
+ //
69
+ // The no-require layout costs one thing, deliberately: the body's
70
+ // first line shares a physical line with the preamble, so a frame
71
+ // reported at line 1 carries a column offset by the preamble's length.
72
+ // Line 1 of a userscript is its `// ==UserScript==` marker, so this
73
+ // has never been observed; the code view suppresses the column accent
74
+ // there rather than showing a wrong one.
75
+ export const USER_SOURCE_START_LINE = 1;
76
+ export function composeSource(script, opts = {}) {
77
+ const mainSource = joinFullSource(script.leadingText ?? '', script.headerText ?? '', script.bodyText);
78
+ const requires = script.requires ?? [];
79
+ const startLine = opts.startLine ?? 0;
80
+ if (requires.length === 0) {
81
+ return {
82
+ text: mainSource,
83
+ segments: [],
84
+ lineCount: countLines(mainSource),
85
+ mainStart: 0,
86
+ };
87
+ }
88
+ // Build the text incrementally and derive every line number from
89
+ // what has ACTUALLY been emitted, rather than adding up expected
90
+ // line counts alongside a `join()`. The two drift: a require whose
91
+ // source ends in a lone `\r` fuses with a joining `\n` into a single
92
+ // CRLF, so one terminator appears where the arithmetic assumed two
93
+ // and every mapping from that seam onward — including the whole user
94
+ // body — shifts by a line. CR-only line endings are exactly the
95
+ // population `\r` is in `LINE_TERMINATORS` for, and nothing
96
+ // normalizes newlines on the way in (file-loader stores the decoded
97
+ // bytes verbatim).
98
+ const segments = [];
99
+ let text = '';
100
+ // 0-based generated line that the NEXT character appended will land
101
+ // on. `countLines('')` is 1, so an empty buffer is line 0.
102
+ const nextLine = () => startLine + countLines(text) - 1;
103
+ for (const [i, r] of requires.entries()) {
104
+ text += `// @require ${r.url}\n`;
105
+ const url = opts.requireUrls?.[i];
106
+ if (url) {
107
+ segments.push({
108
+ url,
109
+ content: r.source,
110
+ generatedLine: nextLine(),
111
+ lineCount: countLines(r.source),
112
+ });
113
+ }
114
+ // The trailing-`\r` guard: append the extra `\n` here so the
115
+ // source's own last line stays a line of its own, instead of being
116
+ // swallowed by the separator that follows.
117
+ text += r.source.endsWith('\r') ? `${r.source}\n` : r.source;
118
+ // Terminate the source's last line, then the `;` seam guard on a
119
+ // line of its own.
120
+ text += '\n;\n';
121
+ }
122
+ if (opts.mainUrl) {
123
+ segments.push({
124
+ url: opts.mainUrl,
125
+ content: mainSource,
126
+ generatedLine: nextLine(),
127
+ lineCount: countLines(mainSource),
128
+ });
129
+ }
130
+ const mainStart = text.length;
131
+ text += mainSource;
132
+ return { text, segments, lineCount: countLines(text), mainStart };
133
+ }
134
+ export function stackLayout(script, logLabel) {
135
+ const entryUrl = buildSourceUrl(logLabel);
136
+ const { segments, lineCount } = composeSource(script, {
137
+ requireUrls: (script.requires ?? []).map((r) => buildRequireSourceUrl(logLabel, r.url)),
138
+ mainUrl: entryUrl,
139
+ startLine: USER_SOURCE_START_LINE,
140
+ });
141
+ return { entryUrl, segments, lineCount };
142
+ }
143
+ // Count lines the way V8 does, which is what the source map has to
144
+ // agree with. Counting only `\n` silently shifts every mapping after
145
+ // the offending character:
146
+ //
147
+ // - a lone `\r` is a line terminator (files with mangled endings);
148
+ // - so are U+2028 / U+2029, and V8 counts a RAW U+2028 as a break
149
+ // even inside a string literal (legal since ES2019, and minified
150
+ // CDN bundles do embed them).
151
+ //
152
+ // `\r\n` must count as one, hence the alternation order.
153
+ const LINE_TERMINATORS = /\r\n|[\n\r\u2028\u2029]/g;
154
+ // `buildParseCheckSource` below measures its own preamble with it: a
155
+ // parse-check line offset that counted terminators differently from the
156
+ // segment list it is compared against would misattribute every error in
157
+ // the file.
158
+ function countLines(text) {
159
+ if (text === '')
160
+ return 1;
161
+ const matches = text.match(LINE_TERMINATORS);
162
+ return matches ? matches.length + 1 : 1;
163
+ }
164
+ // Public entry point for the swap-eval path, which needs the text only.
165
+ export function composeRequiredBody(script) {
166
+ return composeSource(script).text;
167
+ }
168
+ export function buildParseCheckSource(script) {
169
+ // A blank first line of our own, so the user's first line is never at
170
+ // offset 0: a `#!` hashbang is legal only there, so it stays the
171
+ // syntax error it also is in the real injected entry (which wraps the
172
+ // source), and the location probes can't be handed a source that
173
+ // parses as a shebang script. Blank, not a statement, so a leading
174
+ // `"use strict"` still applies, as in the injected entry (see
175
+ // USER_SCOPE_OPEN in injector.ts). The offset below is derived from it rather than
176
+ // assumed to be 1 — the same discipline `composeSource` applies
177
+ // internally, and for the same reason: assumed line counts drift
178
+ // from emitted ones.
179
+ const preamble = '\n';
180
+ const startLine = countLines(preamble) - 1;
181
+ const requires = script.requires ?? [];
182
+ const composed = composeSource(script, {
183
+ requireUrls: requires.map((r) => r.url),
184
+ mainUrl: script.relativePath,
185
+ startLine,
186
+ });
187
+ return {
188
+ text: preamble + composed.text,
189
+ // `composeSource` emits no segments for a script with no
190
+ // `@require`s — the viewer keys "pass stack refs through unmapped"
191
+ // off exactly that, so it stays as it is. Here the opposite is
192
+ // wanted: one segment for the body means every reported line
193
+ // resolves through the same lookup, with no second code path for
194
+ // the majority of scripts.
195
+ segments: composed.segments.length > 0
196
+ ? composed.segments
197
+ : [{
198
+ url: script.relativePath,
199
+ content: composed.text,
200
+ generatedLine: startLine,
201
+ lineCount: composed.lineCount,
202
+ }],
203
+ lineCount: startLine + composed.lineCount,
204
+ };
205
+ }
@@ -0,0 +1,47 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>SourceMonkey | Network permission required</title>
6
+ <link rel="stylesheet" href="styles.css" />
7
+ <style>
8
+ body { font: 14px system-ui, sans-serif; margin: 0; color: #222; background: #fff; --page-width: 100%; }
9
+ .page-body { padding: 14px 16px; }
10
+ p { margin: 0 0 10px; line-height: 18px; }
11
+ .target { font-weight: 600; overflow-wrap: anywhere; }
12
+ .question { font-weight: 600; margin-top: 14px; }
13
+ .actions { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 4px; }
14
+ .actions button { padding: 0 11px; }
15
+ .actions button.primary { font-weight: 600; }
16
+ #error { color: #b00020; }
17
+ a { color: #0b57d0; }
18
+ </style>
19
+ </head>
20
+ <body>
21
+ <header class="page-header">
22
+ <div class="page-header-inner">
23
+ <img class="page-icon" src="icons/icon-48.png" alt="" />
24
+ <h1><span class="brand">SourceMonkey |</span> Network permission required</h1>
25
+ </div>
26
+ </header>
27
+ <div class="page-body">
28
+ <p>Script <a id="script" class="target" href="#" target="_blank" rel="noopener"></a>
29
+ is requesting access to <a id="site" class="target" href="#" target="_blank" rel="noopener"></a>.</p>
30
+ <p>Granting this permission allows the script to act as you on the target page.</p>
31
+ <p>You can revoke permissions on the script's page.</p>
32
+ <p id="error" hidden></p>
33
+ <p class="question">Allow one time?</p>
34
+ <div class="actions">
35
+ <button id="once" type="button" title="Allow this request one time">Allow once</button>
36
+ <button id="cancel" type="button" title="Deny this request one time">Cancel</button>
37
+ </div>
38
+ <p class="question">Allow permanently?</p>
39
+ <div class="actions">
40
+ <button id="allow" type="button" class="primary" title="Allow access to this site every time">Allow</button>
41
+ <button id="deny" type="button" title="Deny access to this site every time">Deny</button>
42
+ <button id="allow-all" type="button" title="Allow this script all access to ALL sites">Allow all sites</button>
43
+ </div>
44
+ </div>
45
+ <script type="module" src="extension/connect-prompt-page.js"></script>
46
+ </body>
47
+ </html>