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.
- package/LICENSE +21 -0
- package/README.md +87 -2
- package/dist/bytes.js +37 -0
- package/dist/channel-placeholder.js +5 -0
- package/dist/collection-scan.js +17 -0
- package/dist/collections.html +353 -0
- package/dist/compare.html +358 -0
- package/dist/composed-source.js +205 -0
- package/dist/connect-prompt.html +47 -0
- package/dist/debug/icons.html +211 -0
- package/dist/debug/storage.html +163 -0
- package/dist/debug-log.js +75 -0
- package/dist/diagnostic-location.js +64 -0
- package/dist/eval-hook.js +308 -0
- package/dist/extension/background.js +5263 -0
- package/dist/extension/channel.js +133 -0
- package/dist/extension/code-links.js +187 -0
- package/dist/extension/code-tabs.js +460 -0
- package/dist/extension/collection-dialog.js +619 -0
- package/dist/extension/collection-display.js +322 -0
- package/dist/extension/collections.js +2905 -0
- package/dist/extension/compare.js +867 -0
- package/dist/extension/concurrency.js +186 -0
- package/dist/extension/connect-grants.js +109 -0
- package/dist/extension/connect-prompt-page.js +70 -0
- package/dist/extension/connect-prompt.js +266 -0
- package/dist/extension/copy-button.js +63 -0
- package/dist/extension/copy-dialog.js +502 -0
- package/dist/extension/copy-preference.js +66 -0
- package/dist/extension/debug/icons.js +203 -0
- package/dist/extension/debug/storage.js +365 -0
- package/dist/extension/deep-link.js +77 -0
- package/dist/extension/delete-dialog.js +432 -0
- package/dist/extension/delete-icon.js +40 -0
- package/dist/extension/details-tooltips.js +66 -0
- package/dist/extension/directories.js +679 -0
- package/dist/extension/export-backup.js +407 -0
- package/dist/extension/export-dialog.js +142 -0
- package/dist/extension/file-access.js +74 -0
- package/dist/extension/file-changes.js +346 -0
- package/dist/extension/frame-info.js +85 -0
- package/dist/extension/github-provider.js +336 -0
- package/dist/extension/glyph.js +84 -0
- package/dist/extension/gm-bindings.js +601 -0
- package/dist/extension/gm-download.js +419 -0
- package/dist/extension/gm-menu.js +228 -0
- package/dist/extension/gm-notification.js +141 -0
- package/dist/extension/gm-originator-map.js +23 -0
- package/dist/extension/gm-tab-data.js +121 -0
- package/dist/extension/gm-tab.js +160 -0
- package/dist/extension/gm-url-change.js +111 -0
- package/dist/extension/gm-url-scheme.js +27 -0
- package/dist/extension/gm-values.js +176 -0
- package/dist/extension/gm-window-control.js +104 -0
- package/dist/extension/gm-xhr-headers.js +333 -0
- package/dist/extension/gm-xhr.js +584 -0
- package/dist/extension/injector.js +3145 -0
- package/dist/extension/install-capture.js +277 -0
- package/dist/extension/line-diff.js +233 -0
- package/dist/extension/local-copy.js +560 -0
- package/dist/extension/local-delete.js +276 -0
- package/dist/extension/location-kinds.js +108 -0
- package/dist/extension/log-format.js +158 -0
- package/dist/extension/managed-changes.js +361 -0
- package/dist/extension/managed-items.js +57 -0
- package/dist/extension/match-index.js +375 -0
- package/dist/extension/missing-scripts.js +66 -0
- package/dist/extension/more-menu.js +109 -0
- package/dist/extension/move-dialog.js +197 -0
- package/dist/extension/offscreen.js +37 -0
- package/dist/extension/options.js +504 -0
- package/dist/extension/page-heading.js +170 -0
- package/dist/extension/page-links.js +199 -0
- package/dist/extension/parse-check-client.js +70 -0
- package/dist/extension/parse-check.js +161 -0
- package/dist/extension/parse-sandbox-host.js +172 -0
- package/dist/extension/parse-sandbox.js +175 -0
- package/dist/extension/popup-commands-open.js +41 -0
- package/dist/extension/popup-view.js +387 -0
- package/dist/extension/popup.js +703 -0
- package/dist/extension/prism-userscript.js +53 -0
- package/dist/extension/refresh-error.js +136 -0
- package/dist/extension/refresh-targets.js +160 -0
- package/dist/extension/related-versions.js +1144 -0
- package/dist/extension/resize-observer-loop.js +19 -0
- package/dist/extension/row-cache.js +387 -0
- package/dist/extension/script-blobs.js +413 -0
- package/dist/extension/script-details.js +658 -0
- package/dist/extension/script-enablement.js +285 -0
- package/dist/extension/script-identity.js +310 -0
- package/dist/extension/script-keys.js +54 -0
- package/dist/extension/script-log-id.js +155 -0
- package/dist/extension/script-log.js +290 -0
- package/dist/extension/script-rejection.js +104 -0
- package/dist/extension/script-sites.js +158 -0
- package/dist/extension/script-store.js +3507 -0
- package/dist/extension/script-updater.js +991 -0
- package/dist/extension/script-url-hash.js +61 -0
- package/dist/extension/select-all.js +37 -0
- package/dist/extension/select-open-guard.js +90 -0
- package/dist/extension/site-icon.js +1261 -0
- package/dist/extension/sm-dev-link.js +302 -0
- package/dist/extension/solo-click.js +58 -0
- package/dist/extension/sticky-numbers.js +188 -0
- package/dist/extension/storage-breakdown.js +253 -0
- package/dist/extension/storage-scan.js +86 -0
- package/dist/extension/storage-usage.js +194 -0
- package/dist/extension/structural-keys.js +29 -0
- package/dist/extension/sw-teardown.js +36 -0
- package/dist/extension/tab-status.js +403 -0
- package/dist/extension/toolbar-summary.js +105 -0
- package/dist/extension/user-scripts-access.js +43 -0
- package/dist/extension/userscript.js +3672 -0
- package/dist/extension/value-store.js +204 -0
- package/dist/extension/version-probe-fetch.js +68 -0
- package/dist/extension/worker-client.js +109 -0
- package/dist/extension/worker-ops.js +171 -0
- package/dist/extension/zip-writer.js +24 -0
- package/dist/external-files.js +878 -0
- package/dist/file-loader.js +436 -0
- package/dist/file-locations.js +439 -0
- package/dist/generated-wrappers.js +5 -0
- package/dist/github-auth.js +148 -0
- package/dist/github-urls.js +46 -0
- package/dist/gm-api-catalog.js +217 -0
- package/dist/gm-connect.js +273 -0
- package/dist/gm-xhr-types.js +5 -0
- package/dist/http-read.js +142 -0
- package/dist/icons/icon-128.png +0 -0
- package/dist/icons/icon-16.png +0 -0
- package/dist/icons/icon-48.png +0 -0
- package/dist/local-file-overrides.js +558 -0
- package/dist/manifest.json +38 -0
- package/dist/markup-response.js +126 -0
- package/dist/match-targets.js +305 -0
- package/dist/menu-captions.js +22 -0
- package/dist/offscreen.html +39 -0
- package/dist/options.html +197 -0
- package/dist/parse-check-protocol.js +51 -0
- package/dist/parse-location.js +171 -0
- package/dist/parse-sandbox.html +56 -0
- package/dist/phase-timing.js +155 -0
- package/dist/popup.html +197 -0
- package/dist/public-suffixes.js +6957 -0
- package/dist/run-context.js +31 -0
- package/dist/runtime-messages.js +34 -0
- package/dist/sandboxed-page.js +35 -0
- package/dist/script-build.js +787 -0
- package/dist/script-display.js +383 -0
- package/dist/script-icon.js +43 -0
- package/dist/script-links.js +204 -0
- package/dist/script-source-url.js +214 -0
- package/dist/script-world.js +65 -0
- package/dist/sm-dev-protocol.js +84 -0
- package/dist/source-map.js +177 -0
- package/dist/stack-link.js +138 -0
- package/dist/styles.css +825 -0
- package/dist/unsafe-window-use.js +229 -0
- package/dist/url-match.js +734 -0
- package/dist/userscript-header.js +248 -0
- package/dist/userscript.html +1165 -0
- package/dist/vendor/fflate.LICENSE +21 -0
- package/dist/vendor/fflate.js +2692 -0
- package/dist/vendor/prism/prism-line-numbers.css +1 -0
- package/dist/vendor/prism/prism-line-numbers.js +1 -0
- package/dist/vendor/prism/prism.css +1 -0
- package/dist/vendor/prism/prism.js +1946 -0
- package/dist/version-compare.js +141 -0
- package/dist/version-probe.js +120 -0
- package/lib/build-info.json +1 -0
- package/lib/bytes.d.ts +3 -0
- package/lib/bytes.js +37 -0
- package/lib/channel-placeholder.d.ts +1 -0
- package/lib/channel-placeholder.js +5 -0
- package/lib/collection-scan.d.ts +8 -0
- package/lib/collection-scan.js +17 -0
- package/lib/composed-source.d.ts +28 -0
- package/lib/composed-source.js +205 -0
- package/lib/debug-log.d.ts +9 -0
- package/lib/debug-log.js +75 -0
- package/lib/diagnostic-location.d.ts +8 -0
- package/lib/diagnostic-location.js +64 -0
- package/lib/eval-hook.d.ts +34 -0
- package/lib/eval-hook.js +308 -0
- package/lib/external-files.d.ts +111 -0
- package/lib/external-files.js +878 -0
- package/lib/file-loader.d.ts +48 -0
- package/lib/file-loader.js +436 -0
- package/lib/file-locations.d.ts +44 -0
- package/lib/file-locations.js +439 -0
- package/lib/generated-wrappers.d.ts +11 -0
- package/lib/generated-wrappers.js +5 -0
- package/lib/github-auth.d.ts +12 -0
- package/lib/github-auth.js +148 -0
- package/lib/github-urls.d.ts +1 -0
- package/lib/github-urls.js +46 -0
- package/lib/gm-api-catalog.d.ts +24 -0
- package/lib/gm-api-catalog.js +217 -0
- package/lib/gm-connect.d.ts +34 -0
- package/lib/gm-connect.js +273 -0
- package/lib/gm-xhr-types.d.ts +68 -0
- package/lib/gm-xhr-types.js +5 -0
- package/lib/harness/browser-extensions.d.ts +73 -0
- package/lib/harness/browser-extensions.js +285 -0
- package/lib/harness/browser-lang.d.ts +20 -0
- package/lib/harness/browser-lang.js +86 -0
- package/lib/harness/browser-launch.d.ts +14 -0
- package/lib/harness/browser-launch.js +184 -0
- package/lib/harness/checks.d.ts +110 -0
- package/lib/harness/checks.js +321 -0
- package/lib/harness/cli.d.ts +2 -0
- package/lib/harness/cli.js +2259 -0
- package/lib/harness/command-args.d.ts +91 -0
- package/lib/harness/command-args.js +369 -0
- package/lib/harness/command-lines.d.ts +80 -0
- package/lib/harness/command-lines.js +180 -0
- package/lib/harness/command-list.d.ts +206 -0
- package/lib/harness/command-list.js +1475 -0
- package/lib/harness/console-commands.d.ts +463 -0
- package/lib/harness/console-commands.js +3216 -0
- package/lib/harness/download-watch.d.ts +21 -0
- package/lib/harness/download-watch.js +156 -0
- package/lib/harness/extension-backend.d.ts +41 -0
- package/lib/harness/extension-backend.js +100 -0
- package/lib/harness/extension-host.d.ts +112 -0
- package/lib/harness/extension-host.js +552 -0
- package/lib/harness/extension-launch.d.ts +67 -0
- package/lib/harness/extension-launch.js +285 -0
- package/lib/harness/extension-link.d.ts +315 -0
- package/lib/harness/extension-link.js +607 -0
- package/lib/harness/external-manager.d.ts +146 -0
- package/lib/harness/external-manager.js +414 -0
- package/lib/harness/fixture.d.ts +165 -0
- package/lib/harness/fixture.js +461 -0
- package/lib/harness/frame-sessions.d.ts +71 -0
- package/lib/harness/frame-sessions.js +248 -0
- package/lib/harness/frames.d.ts +68 -0
- package/lib/harness/frames.js +216 -0
- package/lib/harness/help-format.d.ts +17 -0
- package/lib/harness/help-format.js +127 -0
- package/lib/harness/host.d.ts +352 -0
- package/lib/harness/host.js +423 -0
- package/lib/harness/index.d.ts +8 -0
- package/lib/harness/index.js +10 -0
- package/lib/harness/input-file.d.ts +18 -0
- package/lib/harness/input-file.js +61 -0
- package/lib/harness/json-output.d.ts +565 -0
- package/lib/harness/json-output.js +71 -0
- package/lib/harness/manager-actions.d.ts +21 -0
- package/lib/harness/manager-actions.js +129 -0
- package/lib/harness/manager-commands.d.ts +142 -0
- package/lib/harness/manager-commands.js +1196 -0
- package/lib/harness/manager-fetch.d.ts +33 -0
- package/lib/harness/manager-fetch.js +239 -0
- package/lib/harness/managers.d.ts +24 -0
- package/lib/harness/managers.js +27 -0
- package/lib/harness/output-style.d.ts +125 -0
- package/lib/harness/output-style.js +322 -0
- package/lib/harness/page-commands.d.ts +134 -0
- package/lib/harness/page-commands.js +1141 -0
- package/lib/harness/page-output.d.ts +67 -0
- package/lib/harness/page-output.js +139 -0
- package/lib/harness/page-watch.d.ts +171 -0
- package/lib/harness/page-watch.js +607 -0
- package/lib/harness/parse-check-node.d.ts +3 -0
- package/lib/harness/parse-check-node.js +132 -0
- package/lib/harness/path-args.d.ts +22 -0
- package/lib/harness/path-args.js +148 -0
- package/lib/harness/playwright-chromium.d.ts +16 -0
- package/lib/harness/playwright-chromium.js +86 -0
- package/lib/harness/prepare.d.ts +168 -0
- package/lib/harness/prepare.js +364 -0
- package/lib/harness/prompt-editor.d.ts +17 -0
- package/lib/harness/prompt-editor.js +354 -0
- package/lib/harness/prompt-history.d.ts +13 -0
- package/lib/harness/prompt-history.js +89 -0
- package/lib/harness/rebuild-advice.d.ts +6 -0
- package/lib/harness/rebuild-advice.js +39 -0
- package/lib/harness/run-log.d.ts +47 -0
- package/lib/harness/run-log.js +140 -0
- package/lib/harness/run-logs.d.ts +132 -0
- package/lib/harness/run-logs.js +241 -0
- package/lib/harness/run.d.ts +194 -0
- package/lib/harness/run.js +1973 -0
- package/lib/harness/runs.d.ts +229 -0
- package/lib/harness/runs.js +726 -0
- package/lib/harness/save-html.d.ts +39 -0
- package/lib/harness/save-html.js +89 -0
- package/lib/harness/saved-pages.d.ts +120 -0
- package/lib/harness/saved-pages.js +275 -0
- package/lib/harness/script-mark.d.ts +17 -0
- package/lib/harness/script-mark.js +56 -0
- package/lib/harness/snapshot.d.ts +143 -0
- package/lib/harness/snapshot.js +474 -0
- package/lib/harness/stuck-tabs.d.ts +19 -0
- package/lib/harness/stuck-tabs.js +131 -0
- package/lib/harness/tab-refs.d.ts +20 -0
- package/lib/harness/tab-refs.js +80 -0
- package/lib/harness/tampermonkey.d.ts +71 -0
- package/lib/harness/tampermonkey.js +356 -0
- package/lib/harness/tm-ids.d.ts +18 -0
- package/lib/harness/tm-ids.js +88 -0
- package/lib/harness/violentmonkey.d.ts +34 -0
- package/lib/harness/violentmonkey.js +162 -0
- package/lib/harness/wait.d.ts +77 -0
- package/lib/harness/wait.js +458 -0
- package/lib/http-read.d.ts +30 -0
- package/lib/http-read.js +142 -0
- package/lib/local-file-overrides.d.ts +35 -0
- package/lib/local-file-overrides.js +558 -0
- package/lib/manifest.json +38 -0
- package/lib/markup-response.d.ts +11 -0
- package/lib/markup-response.js +126 -0
- package/lib/match-targets.d.ts +18 -0
- package/lib/match-targets.js +305 -0
- package/lib/menu-captions.d.ts +1 -0
- package/lib/menu-captions.js +22 -0
- package/lib/parse-check-protocol.d.ts +27 -0
- package/lib/parse-check-protocol.js +51 -0
- package/lib/parse-location.d.ts +12 -0
- package/lib/parse-location.js +171 -0
- package/lib/phase-timing.d.ts +12 -0
- package/lib/phase-timing.js +155 -0
- package/lib/public-suffixes.d.ts +1 -0
- package/lib/public-suffixes.js +6957 -0
- package/lib/run-context.d.ts +2 -0
- package/lib/run-context.js +31 -0
- package/lib/runtime-messages.d.ts +10 -0
- package/lib/runtime-messages.js +34 -0
- package/lib/sandboxed-page.d.ts +5 -0
- package/lib/sandboxed-page.js +35 -0
- package/lib/script-build.d.ts +111 -0
- package/lib/script-build.js +787 -0
- package/lib/script-display.d.ts +51 -0
- package/lib/script-display.js +383 -0
- package/lib/script-icon.d.ts +16 -0
- package/lib/script-icon.js +43 -0
- package/lib/script-links.d.ts +24 -0
- package/lib/script-links.js +204 -0
- package/lib/script-source-url.d.ts +8 -0
- package/lib/script-source-url.js +214 -0
- package/lib/script-world.d.ts +6 -0
- package/lib/script-world.js +65 -0
- package/lib/sm-dev-protocol.d.ts +251 -0
- package/lib/sm-dev-protocol.js +84 -0
- package/lib/source-map.d.ts +32 -0
- package/lib/source-map.js +177 -0
- package/lib/stack-link.d.ts +15 -0
- package/lib/stack-link.js +138 -0
- package/lib/unsafe-window-use.d.ts +1 -0
- package/lib/unsafe-window-use.js +229 -0
- package/lib/url-match.d.ts +40 -0
- package/lib/url-match.js +734 -0
- package/lib/userscript-header.d.ts +33 -0
- package/lib/userscript-header.js +248 -0
- package/lib/version-compare.d.ts +6 -0
- package/lib/version-compare.js +141 -0
- package/lib/version-probe.d.ts +17 -0
- package/lib/version-probe.js +120 -0
- package/package.json +55 -3
- package/skills/SourceMonkey-dev/SKILL.md +868 -0
- package/skills/SourceMonkey-dev/references/cdp.md +293 -0
- package/skills/SourceMonkey-dev/references/commands.md +297 -0
- package/skills/SourceMonkey-dev/references/other-managers.md +63 -0
- package/skills/SourceMonkey-dev/references/specs.md +46 -0
- package/skills/SourceMonkey-friction/SKILL.md +103 -0
- package/skills/SourceMonkey-friction/references/template.md +59 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
// The development harness's front door: a userscript on disk (or as
|
|
2
|
+
// text) in, a checked script out.
|
|
3
|
+
//
|
|
4
|
+
// This runs SourceMonkey's real install pipeline under Node — the same
|
|
5
|
+
// functions the extension calls when it installs or refreshes a script:
|
|
6
|
+
//
|
|
7
|
+
// 1. `buildScriptFromText` splits the metadata block, parses and
|
|
8
|
+
// validates the header, and derives the matching rules.
|
|
9
|
+
// 2. `applyFiles` resolves and fetches every `@require` / `@resource`,
|
|
10
|
+
// with the same local-file overrides the extension applies to a
|
|
11
|
+
// script loaded from disk (a `@require https://…/lib/x.js` reads
|
|
12
|
+
// the local `lib/x.js` when one sits under a search root).
|
|
13
|
+
// 3. The parse check compiles the composed program without running
|
|
14
|
+
// it, so a syntax error is reported against the file and line it
|
|
15
|
+
// was written in — under Node's V8 rather than Chrome's, which is
|
|
16
|
+
// the one piece that differs (see parse-check-node.ts).
|
|
17
|
+
//
|
|
18
|
+
// The extension itself builds what runs (sm-dev pushes the script's
|
|
19
|
+
// text); this is for checking a script up front and reading it back.
|
|
20
|
+
//
|
|
21
|
+
// Nothing here touches `chrome.*`. The two globals the pipeline reaches
|
|
22
|
+
// for are replaced once per process: `fetch`, which Node doesn't
|
|
23
|
+
// implement for `file://` URLs, and the parse checker, which the
|
|
24
|
+
// extension installs from a sandboxed page.
|
|
25
|
+
import { statSync } from 'node:fs';
|
|
26
|
+
import { readFile } from 'node:fs/promises';
|
|
27
|
+
import path from 'node:path';
|
|
28
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
29
|
+
import { applyFiles, buildScriptFromText, setParseChecker, } from '../script-build.js';
|
|
30
|
+
import { attachParseLocation } from '../parse-location.js';
|
|
31
|
+
import { describeDiagnostic } from '../diagnostic-location.js';
|
|
32
|
+
import { setConfiguredLocalRoots } from '../local-file-overrides.js';
|
|
33
|
+
import { explainUrlMatch } from '../url-match.js';
|
|
34
|
+
import { hasTag } from '../userscript-header.js';
|
|
35
|
+
import { scriptBasename } from '../script-display.js';
|
|
36
|
+
import { representativeMatch } from '../match-targets.js';
|
|
37
|
+
import { bytesToBase64, sha256Hex } from '../bytes.js';
|
|
38
|
+
import { buildParseCheckSource } from '../composed-source.js';
|
|
39
|
+
import { resolveScriptWorld } from '../script-world.js';
|
|
40
|
+
import { checkParseNode } from './parse-check-node.js';
|
|
41
|
+
import { MANIFEST_FILENAME } from '../collection-scan.js';
|
|
42
|
+
import { WARNING_LEVEL } from './output-style.js';
|
|
43
|
+
// ---------- The two process-wide seams ----------
|
|
44
|
+
let seamsInstalled = false;
|
|
45
|
+
// Per-call state the seams read. Safe as module state only because
|
|
46
|
+
// `prepareScript` serializes calls.
|
|
47
|
+
let fetchOverride;
|
|
48
|
+
let parseCheckNote;
|
|
49
|
+
// `file-loader.ts` reads every dependency through the global `fetch`,
|
|
50
|
+
// which Node doesn't implement for `file://`. Wrap it once; http(s)
|
|
51
|
+
// passes straight through to the real one.
|
|
52
|
+
function installNodeSeams() {
|
|
53
|
+
if (seamsInstalled)
|
|
54
|
+
return;
|
|
55
|
+
seamsInstalled = true;
|
|
56
|
+
const realFetch = globalThis.fetch;
|
|
57
|
+
globalThis.fetch = async (input, init) => {
|
|
58
|
+
const url = typeof input === 'string' ? input
|
|
59
|
+
: input instanceof URL ? input.href
|
|
60
|
+
: input.url;
|
|
61
|
+
if (fetchOverride)
|
|
62
|
+
return fetchOverride(url);
|
|
63
|
+
if (!url.startsWith('file:'))
|
|
64
|
+
return realFetch(input, init);
|
|
65
|
+
let body;
|
|
66
|
+
try {
|
|
67
|
+
const buf = await readFile(fileURLToPath(url));
|
|
68
|
+
body = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return new Response(null, { status: 404 });
|
|
72
|
+
}
|
|
73
|
+
// No Content-Type, as Chrome's own `file://` fetch has none: the
|
|
74
|
+
// loader's markup sniff is the gate for local files either way, and
|
|
75
|
+
// a header invented here would make the stored row differ from the
|
|
76
|
+
// extension's.
|
|
77
|
+
return new Response(body, {
|
|
78
|
+
status: 200,
|
|
79
|
+
headers: { 'content-length': String(body.byteLength) },
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
// Same two steps the extension's checkers perform: compose the exact
|
|
83
|
+
// text the injected entry compiles, then map the reported position
|
|
84
|
+
// back to the file it was written in. Only the compile is Node's.
|
|
85
|
+
//
|
|
86
|
+
// The pipeline swallows a check that couldn't decide (it fails
|
|
87
|
+
// open), so the note is kept here for `validate` to show.
|
|
88
|
+
setParseChecker(async (script) => {
|
|
89
|
+
let checked;
|
|
90
|
+
try {
|
|
91
|
+
checked = buildParseCheckSource(script);
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
parseCheckNote = { kind: 'errored', message: String(err?.message ?? err) };
|
|
95
|
+
throw err;
|
|
96
|
+
}
|
|
97
|
+
const verdict = attachParseLocation(checkParseNode(checked.text), checked);
|
|
98
|
+
if (verdict?.status === 'unknown')
|
|
99
|
+
parseCheckNote = { kind: 'inconclusive', message: verdict.message ?? '' };
|
|
100
|
+
return verdict;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
// ---------- Preparing ----------
|
|
104
|
+
// Calls are serialized: the override resolver's configured roots and
|
|
105
|
+
// the parse checker are process-wide, and two overlapping prepares with
|
|
106
|
+
// different `localRoots` would otherwise read each other's. A spec that
|
|
107
|
+
// prepares several scripts with `Promise.all` still gets each one
|
|
108
|
+
// resolved against its own roots.
|
|
109
|
+
let chain = Promise.resolve();
|
|
110
|
+
export function prepareScript(opts) {
|
|
111
|
+
const run = chain.then(async () => {
|
|
112
|
+
fetchOverride = opts.fetch;
|
|
113
|
+
parseCheckNote = undefined;
|
|
114
|
+
try {
|
|
115
|
+
return await prepareScriptNow(opts);
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
fetchOverride = undefined;
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
chain = run.catch(() => undefined);
|
|
122
|
+
return run;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* The roots to prepare `file` with, given `collectionRoot` and
|
|
126
|
+
* `localRoots`. A script outside the root it was given (sm-dev run in
|
|
127
|
+
* one repo on another's script, or a shared fixture's root) belongs to
|
|
128
|
+
* the collection whose `script_manifest.json` is nearest above it, as
|
|
129
|
+
* it would be installed. The given root then joins the local roots, so
|
|
130
|
+
* its `lib/` still stands in for the `@require`s that name it.
|
|
131
|
+
*/
|
|
132
|
+
export function scriptRoots(file, collectionRoot, localRoots = []) {
|
|
133
|
+
const abs = path.resolve(file);
|
|
134
|
+
const root = path.resolve(collectionRoot);
|
|
135
|
+
if (isUnder(abs, root))
|
|
136
|
+
return { collectionRoot, localRoots };
|
|
137
|
+
for (let dir = path.dirname(abs); dir !== path.dirname(dir); dir = path.dirname(dir)) {
|
|
138
|
+
if (statSync(path.join(dir, MANIFEST_FILENAME), { throwIfNoEntry: false })?.isFile()) {
|
|
139
|
+
return { collectionRoot: dir, localRoots: [...localRoots, root] };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { collectionRoot, localRoots };
|
|
143
|
+
}
|
|
144
|
+
async function prepareScriptNow(given) {
|
|
145
|
+
const opts = given.file && given.collectionRoot
|
|
146
|
+
? { ...given, ...scriptRoots(given.file, given.collectionRoot, given.localRoots) }
|
|
147
|
+
: given;
|
|
148
|
+
installNodeSeams();
|
|
149
|
+
if (!opts.file && opts.text === undefined) {
|
|
150
|
+
throw new Error('Pass prepareScript a file or text');
|
|
151
|
+
}
|
|
152
|
+
const text = opts.text ?? await readFile(opts.file, 'utf8');
|
|
153
|
+
const sourceUrl = opts.sourceUrl
|
|
154
|
+
?? (opts.file ? pathToFileURL(path.resolve(opts.file)).toString()
|
|
155
|
+
: pathToFileURL(path.join(opts.collectionRoot ?? process.cwd(), 'pushed.user.js')).toString());
|
|
156
|
+
const relativePath = relativePathFor(opts, sourceUrl);
|
|
157
|
+
const now = Date.now();
|
|
158
|
+
// The configured roots are process-wide state in the override
|
|
159
|
+
// resolver (the extension reads them from storage once), so they are
|
|
160
|
+
// set on every call; `prepareScript` serializes calls for the same
|
|
161
|
+
// reason.
|
|
162
|
+
setConfiguredLocalRoots((opts.localRoots ?? []).map(dirUrl));
|
|
163
|
+
const built = await buildScriptFromText({
|
|
164
|
+
// Stable across re-prepares of the same file, so the host keeps
|
|
165
|
+
// that script's values and records under one key, and distinct for
|
|
166
|
+
// two scripts sharing a basename, so the host tells them apart.
|
|
167
|
+
id: `harness-${scriptBasename(relativePath)}-${(await sha256Hex(sourceUrl + (opts.copy ?? ''))).slice(0, 12)}`,
|
|
168
|
+
collectionId: 'harness',
|
|
169
|
+
relativePath,
|
|
170
|
+
fileUrl: sourceUrl,
|
|
171
|
+
text,
|
|
172
|
+
now,
|
|
173
|
+
});
|
|
174
|
+
// A fresh install: no prior row, every dependency refetched. The
|
|
175
|
+
// collection root joins the search roots the way it does for a
|
|
176
|
+
// directory collection in the extension.
|
|
177
|
+
const script = await applyFiles(built, undefined, 'all', new Map(), now, {
|
|
178
|
+
enabled: opts.localFiles !== false,
|
|
179
|
+
collectionPath: opts.collectionRoot ? dirUrl(opts.collectionRoot) : undefined,
|
|
180
|
+
});
|
|
181
|
+
const out = {
|
|
182
|
+
script,
|
|
183
|
+
status: script.status,
|
|
184
|
+
startupLogs: script.startupLogs ?? [],
|
|
185
|
+
...(parseCheckNote && { parseCheckNote }),
|
|
186
|
+
id: script.status === 'ok' ? script.id : undefined,
|
|
187
|
+
world: resolveScriptWorld(script),
|
|
188
|
+
matching: script.matching,
|
|
189
|
+
requires: (script.requires ?? []).map((r) => ({ url: r.url, localUrl: r.localUrl })),
|
|
190
|
+
};
|
|
191
|
+
if (script.errorMessage) {
|
|
192
|
+
out.errorMessage = script.errorMessage;
|
|
193
|
+
out.errorLocation = script.errorLocation;
|
|
194
|
+
out.diagnostic = describeDiagnostic(script.errorMessage, script.errorLocation);
|
|
195
|
+
}
|
|
196
|
+
return out;
|
|
197
|
+
}
|
|
198
|
+
// The path the extension would store for this script: relative to the
|
|
199
|
+
// collection root when it sits under one, else just its name. The
|
|
200
|
+
// diagnostics, the composed-source segments, and `GM_info` all carry
|
|
201
|
+
// it, so sm-dev's output reads the same as the extension's Log tab.
|
|
202
|
+
function relativePathFor(opts, sourceUrl) {
|
|
203
|
+
if (!opts.file)
|
|
204
|
+
return scriptBasename(sourceUrl);
|
|
205
|
+
const file = path.resolve(opts.file);
|
|
206
|
+
if (opts.collectionRoot) {
|
|
207
|
+
const root = path.resolve(opts.collectionRoot);
|
|
208
|
+
if (file !== root && isUnder(file, root))
|
|
209
|
+
return path.relative(root, file).split(path.sep).join('/');
|
|
210
|
+
}
|
|
211
|
+
return path.basename(file);
|
|
212
|
+
}
|
|
213
|
+
// Whether `file` is `dir` or inside it. Not by a `..` prefix alone,
|
|
214
|
+
// which a child named `..cache` also has.
|
|
215
|
+
function isUnder(file, dir) {
|
|
216
|
+
const rel = path.relative(dir, file);
|
|
217
|
+
return rel !== '..' && !rel.startsWith(`..${path.sep}`) && !path.isAbsolute(rel);
|
|
218
|
+
}
|
|
219
|
+
// A directory as the `file://` URL the override resolver wants, with
|
|
220
|
+
// the trailing slash it keys on.
|
|
221
|
+
function dirUrl(dir) {
|
|
222
|
+
const url = pathToFileURL(path.resolve(dir)).toString();
|
|
223
|
+
return url.endsWith('/') ? url : url + '/';
|
|
224
|
+
}
|
|
225
|
+
/** What a `ParseCheckNote` means for the person reading it. */
|
|
226
|
+
export function parseCheckWarning(note) {
|
|
227
|
+
const why = note.message ? ` (${note.message})` : '';
|
|
228
|
+
return `The syntax check could not finish${why}, so syntax errors were not checked. The script still loads.`;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Every warning from preparing the script, as `<level>: <message>`
|
|
232
|
+
* with the line each is about: the load-time notes the viewer's Log
|
|
233
|
+
* tab shows, then (unless `parseCheck` is false) a syntax check that
|
|
234
|
+
* couldn't decide.
|
|
235
|
+
*/
|
|
236
|
+
export function warningLines(prepared, { parseCheck = true } = {}) {
|
|
237
|
+
const lines = prepared.startupLogs.map((l) => `${l.level}: ${describeDiagnostic(l.message, l.location)}`);
|
|
238
|
+
if (parseCheck && prepared.parseCheckNote)
|
|
239
|
+
lines.push(`${WARNING_LEVEL}${parseCheckWarning(prepared.parseCheckNote)}`);
|
|
240
|
+
return lines;
|
|
241
|
+
}
|
|
242
|
+
/** The reason to give when no header rule names a URL at all. */
|
|
243
|
+
export const NO_RULE_COVERS_URL = 'No @match or @include covers this URL';
|
|
244
|
+
/** The same, for `match` over several URLs, none of which a rule names. */
|
|
245
|
+
export const NO_RULE_COVERS_URLS = 'No @match or @include covers these URLs';
|
|
246
|
+
/**
|
|
247
|
+
* Whether the script runs on `url`, and which header rule decided: an
|
|
248
|
+
* exclude wins over everything, then the first `@match`, then the
|
|
249
|
+
* first `@include`. Also every rule that matched or excluded it
|
|
250
|
+
* (`matchedBy`, `excludedBy`). The extension's own matcher, so the
|
|
251
|
+
* answer is the one the extension would give.
|
|
252
|
+
*/
|
|
253
|
+
export function explainMatch(matching, url) {
|
|
254
|
+
return explainUrlMatch(url, matching);
|
|
255
|
+
}
|
|
256
|
+
/** A script path that names nothing, for `start` and the typed `load`. */
|
|
257
|
+
export function noSuchFileMessage(input) {
|
|
258
|
+
return `No such file or directory: ${input}`;
|
|
259
|
+
}
|
|
260
|
+
/** A script path that names a directory, for `start` and the typed `load`. */
|
|
261
|
+
export function isDirectoryMessage(input, remedy = 'Name a .user.js file.') {
|
|
262
|
+
return `${input} is a directory. ${remedy}`;
|
|
263
|
+
}
|
|
264
|
+
/** Why a script has no default page, as `--all` and `newtab all` report it. */
|
|
265
|
+
export const NO_DEFAULT_PAGE = 'Its @match names no page to open';
|
|
266
|
+
/**
|
|
267
|
+
* The page a script is opened on when no URL is given: the first one
|
|
268
|
+
* its `@match` implies. Null when none names a page, as with a
|
|
269
|
+
* match-everything pattern.
|
|
270
|
+
*/
|
|
271
|
+
export function defaultPageUrl(script) {
|
|
272
|
+
return representativeMatch(script.matching)?.linkUrl ?? null;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* A typed URL with `http://` added when it has no scheme, so
|
|
276
|
+
* `example.com/x` works. Only a word that starts with a host reads so:
|
|
277
|
+
* one with a dot, `localhost`, a port (`localhost:8080/x`) or an IPv6
|
|
278
|
+
* address (`[::1]/x`). Any other is a path, made a `file://` URL: one
|
|
279
|
+
* starting `/` or `.`, one naming a file that exists in `cwd`, or one
|
|
280
|
+
* whose first part has no dot (`pages/x.html`), existing or not. `host:port` would
|
|
281
|
+
* otherwise read as a scheme, so only a scheme followed by `//`, or one
|
|
282
|
+
* of the kinds that never have it, counts.
|
|
283
|
+
*/
|
|
284
|
+
export function withDefaultScheme(url, cwd = process.cwd()) {
|
|
285
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(url))
|
|
286
|
+
return url;
|
|
287
|
+
if (/^(about|blob|data|file|javascript|mailto|view-source):/i.test(url))
|
|
288
|
+
return url;
|
|
289
|
+
if (/^[./]/.test(url) || isLocalPath(url, cwd))
|
|
290
|
+
return pathToFileURL(path.resolve(cwd, url)).toString();
|
|
291
|
+
return `http://${url}`;
|
|
292
|
+
}
|
|
293
|
+
// A scheme-less word that is a file in `cwd`, or doesn't start with a
|
|
294
|
+
// host. A web address's host has a dot, except `localhost`; and a
|
|
295
|
+
// directory is rarely named with one, so a first part with a dot reads
|
|
296
|
+
// as a host even when a repo has a folder by that name (`example.com/`).
|
|
297
|
+
function isLocalPath(input, cwd) {
|
|
298
|
+
try {
|
|
299
|
+
if (statSync(path.resolve(cwd, input)).isFile())
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
// Not a file here; the first part decides.
|
|
304
|
+
}
|
|
305
|
+
const first = input.split('/')[0];
|
|
306
|
+
return !(first.includes('.') || /^localhost$/i.test(first) || /:\d+$/.test(first) || first.startsWith('['));
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* A path to show: relative to `cwd` when it's inside it, else
|
|
310
|
+
* `outside` (by default the full path). Never one climbing out with
|
|
311
|
+
* `../`, which is harder to read than either.
|
|
312
|
+
*/
|
|
313
|
+
export function shownPath(file, cwd = process.cwd(), outside = file) {
|
|
314
|
+
const relative = path.relative(cwd, file);
|
|
315
|
+
const inside = relative !== '' && relative !== '..' && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
316
|
+
return inside ? relative : outside;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Where a loaded script is, to show beside its name (`shownPath`).
|
|
320
|
+
* Its `relativePath` stays what identifies it, as in the extension.
|
|
321
|
+
*/
|
|
322
|
+
export function preparedScriptPath(script) {
|
|
323
|
+
const url = script.script.fileUrl;
|
|
324
|
+
return url.startsWith('file:') ? shownPath(fileURLToPath(url)) : script.script.relativePath;
|
|
325
|
+
}
|
|
326
|
+
/** The script's `@name`, else the path it was loaded from. */
|
|
327
|
+
export function preparedScriptName(script) {
|
|
328
|
+
const tags = script.script.header?.tags ?? [];
|
|
329
|
+
const name = tags.find((t) => t.tag === 'name' && !t.locale)?.value;
|
|
330
|
+
return name || script.script.relativePath;
|
|
331
|
+
}
|
|
332
|
+
/** Whether the script has `@noframes`, which keeps it to the top frame. */
|
|
333
|
+
export function preparedNoframes(script) {
|
|
334
|
+
return script.script.header ? hasTag(script.script.header, 'noframes') : false;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Whether `name` picks out this script: the path it was loaded from,
|
|
338
|
+
* its basename, or its `@name`. How a test or a typed command names
|
|
339
|
+
* one script among several.
|
|
340
|
+
*/
|
|
341
|
+
export function preparedScriptMatches(script, name) {
|
|
342
|
+
return script.script.relativePath === name
|
|
343
|
+
|| path.basename(script.script.relativePath) === name
|
|
344
|
+
|| script.script.header?.tags.some((t) => t.tag === 'name' && !t.locale && t.value === name) === true;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* The `@require` / `@resource` bodies a run pushes into SourceMonkey with
|
|
348
|
+
* the script's text, by the ref its header declares: those read from
|
|
349
|
+
* disk, a relative ref's file or a local stand-in for a remote URL,
|
|
350
|
+
* which the extension couldn't read itself. Remote ones it fetches.
|
|
351
|
+
*/
|
|
352
|
+
export function pushedFiles(prepared) {
|
|
353
|
+
const out = {};
|
|
354
|
+
const add = (ref, file, bytesBase64) => {
|
|
355
|
+
if (!file.localUrl && !file.url.startsWith('file:'))
|
|
356
|
+
return;
|
|
357
|
+
out[ref] = { url: file.url, ...(file.localUrl ? { localUrl: file.localUrl } : {}), bytesBase64, contentType: file.contentType ?? '' };
|
|
358
|
+
};
|
|
359
|
+
for (const r of prepared.script.requires ?? [])
|
|
360
|
+
add(r.ref, r, bytesToBase64(new TextEncoder().encode(r.source)));
|
|
361
|
+
for (const r of prepared.script.resources ?? [])
|
|
362
|
+
add(r.ref, r, r.bytesBase64);
|
|
363
|
+
return out;
|
|
364
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import readline from 'node:readline';
|
|
2
|
+
/** How to color the prompts (`> `, `... `) and the typed text, at a terminal that has color. */
|
|
3
|
+
export interface PromptPaint {
|
|
4
|
+
prompt: (text: string) => string;
|
|
5
|
+
text: (text: string) => string;
|
|
6
|
+
}
|
|
7
|
+
export interface PromptEditor {
|
|
8
|
+
/** Empties the buffer, as Ctrl-C and Esc do. */
|
|
9
|
+
clear(): void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Makes `rl` edit several lines as one buffer. `complete` says whether
|
|
13
|
+
* a buffer is ready to send, rather than inside an unclosed block.
|
|
14
|
+
* `cleared` gets the text of a buffer emptied by `clear`. `paint`
|
|
15
|
+
* colors the prompts and the typed text as they are drawn.
|
|
16
|
+
*/
|
|
17
|
+
export declare function editMultiLine(rl: readline.Interface, continuation: string, complete: (text: string) => boolean, cleared?: (text: string) => void, paint?: PromptPaint): PromptEditor;
|