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,229 @@
1
+ // Does a script's own source reference `unsafeWindow` without granting
2
+ // it?
3
+ //
4
+ // `@grant unsafeWindow` is how a script is *supposed* to ask for the
5
+ // page's window, and it is what gets the script the binding. Plenty of
6
+ // real scripts never declare it: `unsafeWindow` is implicitly available under Tampermonkey and
7
+ // Violentmonkey — neither keys it off a grant line, measured under TM
8
+ // 5.5.0 and VM 2.49.0 by `tests/examples/unsafe-window/ungranted.user.js`
9
+ // — so an author who only ever tested there has no reason to add one.
10
+ //
11
+ // Measured over the GreasyFork top 2000: 112 scripts use `unsafeWindow`
12
+ // with no grant for it. Without the binding, the identifier is a
13
+ // `ReferenceError`, so honoring the reference is what makes those
14
+ // scripts run at all.
15
+ //
16
+ // This is a text scan, not a parse. We have no JS parser in the
17
+ // extension (the install-time check compiles with `new Function` in a
18
+ // sandboxed page and reports only a verdict — see docs/parse-check.md),
19
+ // and the answer is needed on the storage row. So:
20
+ //
21
+ // - Comments and string / template literals are stripped first, so a
22
+ // mention in a comment or a log message gets no binding. That was
23
+ // 13 of the 126 ungranted mentions in the corpus.
24
+ // - A property key, a `#private` member and a `foo.unsafeWindow`
25
+ // access don't count. A false positive only adds an unused
26
+ // `window` alias.
27
+ // - A regex literal is NOT recognized. `/['"]/` therefore opens a
28
+ // string state that runs to the next quote, and a literal ending in
29
+ // `\/\/` reads as a line comment — either can swallow real code.
30
+ // Normally that costs a missed reference, so the script gets no
31
+ // binding. If it swallows a DECLARATION while leaving a use
32
+ // visible, the script gets a binding it shadows anyway, which is
33
+ // harmless. No corpus script hits it.
34
+ // - A script that DECLARES the name — `const unsafeWindow =
35
+ // window.wrappedJSObject || window;`, a real cross-browser idiom —
36
+ // answers false, including in a declarator list or a destructuring
37
+ // pattern. Its references read its own binding, never ours. (Our binding would be
38
+ // harmless beside it: the user program runs in a nested scope, so
39
+ // the script's declaration shadows it. See wrapCombinedEntry in
40
+ // injector.ts.) The check is scope-blind, so a declaration inside a
41
+ // function suppresses the whole script: that direction only costs
42
+ // the feature.
43
+ //
44
+ // Only the script's own body is scanned, not its `@require` bodies: the
45
+ // requires arrive on a later pipeline step (`attachFiles`). See
46
+ // TODO.md.
47
+ const IDENT = /[$\w]/;
48
+ // Strip comments and quoted text, leaving a space in their place so
49
+ // adjacent tokens can't merge into a new identifier.
50
+ //
51
+ // Written to jump between interesting positions rather than walk every
52
+ // character: this runs on every script body that mentions the name, at
53
+ // load time, beside the row's SHA-256. On the corpus's largest body
54
+ // (1.8 MB) the per-character form cost ~200 ms, more than 20x that hash.
55
+ function stripQuotedAndComments(src) {
56
+ // A fresh regex per call — `lastIndex` is state, and this function
57
+ // recurses into template substitutions.
58
+ const delim = /\/\/|\/\*|["'`]/g;
59
+ const parts = [];
60
+ const n = src.length;
61
+ let kept = 0;
62
+ for (let m = delim.exec(src); m !== null; m = delim.exec(src)) {
63
+ const from = m.index;
64
+ let after;
65
+ let replacement = ' ';
66
+ if (m[0] === '//') {
67
+ const nl = src.indexOf('\n', from);
68
+ after = nl === -1 ? n : nl;
69
+ }
70
+ else if (m[0] === '/*') {
71
+ const close = src.indexOf('*/', from + 2);
72
+ after = close === -1 ? n : close + 2;
73
+ }
74
+ else {
75
+ const quote = m[0];
76
+ // The code found inside this template's `${ ... }` substitutions.
77
+ const inner = [];
78
+ let i = from + 1;
79
+ while (i < n) {
80
+ if (src[i] === '\\') {
81
+ i += 2;
82
+ continue;
83
+ }
84
+ if (src[i] === quote) {
85
+ i += 1;
86
+ break;
87
+ }
88
+ // A substitution holds real code, so scan it as code rather
89
+ // than as text.
90
+ if (quote === '`' && src[i] === '$' && src[i + 1] === '{') {
91
+ let depth = 1;
92
+ i += 2;
93
+ const innerStart = i;
94
+ while (i < n && depth > 0) {
95
+ if (src[i] === '{')
96
+ depth += 1;
97
+ else if (src[i] === '}')
98
+ depth -= 1;
99
+ i += 1;
100
+ }
101
+ inner.push(stripQuotedAndComments(src.slice(innerStart, i - 1)));
102
+ continue;
103
+ }
104
+ i += 1;
105
+ }
106
+ after = i;
107
+ if (inner.length > 0)
108
+ replacement = ` ${inner.join(' ')} `;
109
+ }
110
+ if (from > kept)
111
+ parts.push(src.slice(kept, from));
112
+ parts.push(replacement);
113
+ kept = after;
114
+ delim.lastIndex = after;
115
+ }
116
+ if (n > kept)
117
+ parts.push(src.slice(kept, n));
118
+ return parts.join('');
119
+ }
120
+ // A free `unsafeWindow` — not `foo.unsafeWindow`, not `unsafeWindows`,
121
+ // not a member the source happens to have named that.
122
+ function hasFreeReference(code) {
123
+ let from = 0;
124
+ for (;;) {
125
+ const at = code.indexOf('unsafeWindow', from);
126
+ if (at === -1)
127
+ return false;
128
+ from = at + 'unsafeWindow'.length;
129
+ if (IDENT.test(code[from] ?? ''))
130
+ continue;
131
+ // Immediately preceded by an identifier character → the tail of a
132
+ // longer name (`myunsafeWindow`). Whitespace in between means a
133
+ // separate token, which `typeof unsafeWindow` needs to pass.
134
+ if (IDENT.test(code[at - 1] ?? ''))
135
+ continue;
136
+ // Walk back over whitespace: `foo\n .unsafeWindow` is a property,
137
+ // and `#unsafeWindow` is a private class member.
138
+ let before = at - 1;
139
+ while (before >= 0 && /\s/.test(code[before]))
140
+ before -= 1;
141
+ if (code[before] === '.' || code[before] === '#')
142
+ continue;
143
+ // Followed by `:` → a property key (`{ unsafeWindow: window }`) or a
144
+ // label, which declares a name rather than reading the page's. This
145
+ // also skips `cond ? unsafeWindow : other`, and that is the trade we
146
+ // want: a script using the name in a ternary almost always uses it
147
+ // somewhere else too, while a key is the whole mention.
148
+ let next = from;
149
+ while (next < code.length && /\s/.test(code[next]))
150
+ next += 1;
151
+ if (code[next] === ':')
152
+ continue;
153
+ return true;
154
+ }
155
+ }
156
+ // `function unsafeWindow(` / `class unsafeWindow`.
157
+ const DECLARES_AS_CALLABLE = /(?:^|[^$\w.])(?:function|class)\s+unsafeWindow(?![$\w])/;
158
+ const KEYWORD = /(?:^|[^$\w.])(?:var|let|const)(?![$\w])/g;
159
+ // How far past a `var` / `let` / `const` to keep looking for the end of
160
+ // its declarator list. A statement without a `;` (ASI) would otherwise
161
+ // run the scan into the rest of the file; over-running only ever
162
+ // over-suppresses, but there is no reason to pay for it.
163
+ const DECLARATOR_SPAN = 2000;
164
+ // Is `unsafeWindow` a NAME BEING BOUND anywhere in this source, rather
165
+ // than a value being read? A script that binds the name reads its own
166
+ // value, so it gets neither our binding nor the move to MAIN world.
167
+ //
168
+ // Walks each `var` / `let` / `const` declarator list, tracking bracket
169
+ // depth and whether the current declarator has passed its `=`:
170
+ //
171
+ // const unsafeWindow = window → bound (before any `=`)
172
+ // let uw = window, unsafeWindow=uw → bound (the `,` starts a declarator)
173
+ // const { unsafeWindow } = window → bound (pattern, before the `=`)
174
+ // const app = unsafeWindow.thing → read (after the `=`) — by far the
175
+ // commonest real use, and the one
176
+ // thing this must not claim
177
+ // const xs = [1, unsafeWindow] → read (bracketed, after the `=`)
178
+ //
179
+ // Scope-blind on purpose: a declaration inside a function suppresses the
180
+ // whole script. That direction only costs the feature.
181
+ function declaresBinding(code) {
182
+ if (DECLARES_AS_CALLABLE.test(code))
183
+ return true;
184
+ KEYWORD.lastIndex = 0;
185
+ for (let m = KEYWORD.exec(code); m !== null; m = KEYWORD.exec(code)) {
186
+ const limit = Math.min(code.length, m.index + DECLARATOR_SPAN);
187
+ let depth = 0;
188
+ let afterEquals = false;
189
+ let i = KEYWORD.lastIndex;
190
+ while (i < limit) {
191
+ const c = code[i];
192
+ if (c === '(' || c === '[' || c === '{')
193
+ depth += 1;
194
+ else if (c === ')' || c === ']' || c === '}') {
195
+ if (depth === 0)
196
+ break;
197
+ depth -= 1;
198
+ }
199
+ else if (c === ';' && depth === 0)
200
+ break;
201
+ else if (c === ',' && depth === 0)
202
+ afterEquals = false;
203
+ else if (c === '=' && code[i + 1] !== '=' && !'=!<>'.includes(code[i - 1] ?? '')) {
204
+ afterEquals = true;
205
+ }
206
+ else if (c === 'u' && code.startsWith('unsafeWindow', i)) {
207
+ const after = code[i + 'unsafeWindow'.length] ?? '';
208
+ const prev = code[i - 1] ?? '';
209
+ if (!IDENT.test(after) && !IDENT.test(prev) && prev !== '.') {
210
+ if (!afterEquals)
211
+ return true;
212
+ i += 'unsafeWindow'.length;
213
+ continue;
214
+ }
215
+ }
216
+ i += 1;
217
+ }
218
+ }
219
+ return false;
220
+ }
221
+ export function sourceUsesUnsafeWindow(bodyText) {
222
+ // The overwhelmingly common answer, without paying for the scan.
223
+ if (!bodyText || bodyText.indexOf('unsafeWindow') === -1)
224
+ return false;
225
+ const code = stripQuotedAndComments(bodyText);
226
+ if (declaresBinding(code))
227
+ return false;
228
+ return hasFreeReference(code);
229
+ }