@kasperpeulen/vitest-plugin-nextjs 0.0.0-alpha.0 → 0.1.0-alpha.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/README.md +249 -2
- package/dist/_virtual/_rolldown/runtime.js +14 -0
- package/dist/action-ids.d.ts +18 -0
- package/dist/action-ids.js +44 -0
- package/dist/adapter.d.ts +8 -0
- package/dist/adapter.js +12 -0
- package/dist/app-requests.d.ts +63 -0
- package/dist/app-requests.js +253 -0
- package/dist/browser-context.d.ts +24 -0
- package/dist/browser-context.js +157 -0
- package/dist/build-output.d.ts +68 -0
- package/dist/build-output.js +216 -0
- package/dist/build.d.ts +26 -0
- package/dist/build.js +39 -0
- package/dist/built-files.d.ts +9 -0
- package/dist/built-files.js +22 -0
- package/dist/cache.d.ts +44 -0
- package/dist/cache.js +99 -0
- package/dist/client-components.d.ts +3 -0
- package/dist/client-components.js +4 -0
- package/dist/client-file-key.d.ts +5 -0
- package/dist/client-file-key.js +5 -0
- package/dist/client-files.d.ts +83 -0
- package/dist/client-files.js +186 -0
- package/dist/client-graph.d.ts +94 -0
- package/dist/client-graph.js +266 -0
- package/dist/client-modules.d.ts +10 -0
- package/dist/client-modules.js +43 -0
- package/dist/client.d.ts +42 -0
- package/dist/client.js +263 -0
- package/dist/commonjs.d.ts +44 -0
- package/dist/commonjs.js +111 -0
- package/dist/compat/browser/client.d.ts +19 -0
- package/dist/compat/browser/client.js +13 -0
- package/dist/compat/build.d.ts +145 -0
- package/dist/compat/build.js +149 -0
- package/dist/compat/checks.d.ts +16 -0
- package/dist/compat/checks.js +148 -0
- package/dist/compat/patches.d.ts +13 -0
- package/dist/compat/patches.js +30 -0
- package/dist/compat/paths.d.ts +74 -0
- package/dist/compat/paths.js +160 -0
- package/dist/compat/rsc/handlers.d.ts +2 -0
- package/dist/compat/rsc/handlers.js +2 -0
- package/dist/compat/rsc/prerender.d.ts +10 -0
- package/dist/compat/rsc/prerender.js +9 -0
- package/dist/compat/server/headers.d.ts +3 -0
- package/dist/compat/server/headers.js +3 -0
- package/dist/compat/ssr/build-output.d.ts +4 -0
- package/dist/compat/ssr/build-output.js +3 -0
- package/dist/compat/ssr/cache.d.ts +6 -0
- package/dist/compat/ssr/cache.js +6 -0
- package/dist/compat/ssr/handler.d.ts +8 -0
- package/dist/compat/ssr/handler.js +8 -0
- package/dist/compat/ssr/node-server.d.ts +5 -0
- package/dist/compat/ssr/node-server.js +4 -0
- package/dist/compat/ssr/render-errors.d.ts +4 -0
- package/dist/compat/ssr/render-errors.js +4 -0
- package/dist/compat/ssr/senders.d.ts +6 -0
- package/dist/compat/ssr/senders.js +6 -0
- package/dist/compat/types.d.ts +8 -0
- package/dist/compat/types.js +1 -0
- package/dist/compile.d.ts +31 -0
- package/dist/compile.js +140 -0
- package/dist/disk.d.ts +16 -0
- package/dist/disk.js +13 -0
- package/dist/document-loads.d.ts +15 -0
- package/dist/document-loads.js +53 -0
- package/dist/document.d.ts +79 -0
- package/dist/document.js +328 -0
- package/dist/downloads.d.ts +15 -0
- package/dist/downloads.js +71 -0
- package/dist/esm-require.d.ts +11 -0
- package/dist/esm-require.js +32 -0
- package/dist/fast-crypto/index.js +1093 -0
- package/dist/fast-crypto.d.ts +20 -0
- package/dist/fast-crypto.js +151 -0
- package/dist/flight.d.ts +19 -0
- package/dist/flight.js +42 -0
- package/dist/form-submission.d.ts +15 -0
- package/dist/form-submission.js +27 -0
- package/dist/from-page.d.ts +5 -0
- package/dist/from-page.js +44 -0
- package/dist/globals.d.ts +1 -0
- package/dist/globals.js +197 -0
- package/dist/host-document.d.ts +26 -0
- package/dist/host-document.js +34 -0
- package/dist/index.d.ts +280 -0
- package/dist/index.js +281 -0
- package/dist/internal.d.ts +2 -0
- package/dist/internal.js +3 -0
- package/dist/leftovers.d.ts +11 -0
- package/dist/leftovers.js +55 -0
- package/dist/mode.d.ts +169 -0
- package/dist/mode.js +31 -0
- package/dist/node/LICENSES.md +3540 -0
- package/dist/node/assert/strict.js +29 -0
- package/dist/node/assert.js +3044 -0
- package/dist/node/buffer.js +1499 -0
- package/dist/node/child_process.js +45 -0
- package/dist/node/cluster.js +85 -0
- package/dist/node/console.js +96 -0
- package/dist/node/constants.js +495 -0
- package/dist/node/crypto.js +1388 -0
- package/dist/node/dgram.js +78 -0
- package/dist/node/diagnostics_channel.js +122 -0
- package/dist/node/dns/promises.js +129 -0
- package/dist/node/dns.js +137 -0
- package/dist/node/domain.js +43 -0
- package/dist/node/events.js +1155 -0
- package/dist/node/fs/promises.js +40 -0
- package/dist/node/fs.js +10375 -0
- package/dist/node/http.js +326 -0
- package/dist/node/http2.js +305 -0
- package/dist/node/https.js +57 -0
- package/dist/node/inspector/promises.js +66 -0
- package/dist/node/inspector.js +76 -0
- package/dist/node/module.js +205 -0
- package/dist/node/net.js +392 -0
- package/dist/node/os.js +259 -0
- package/dist/node/path/posix.js +25 -0
- package/dist/node/path/win32.js +25 -0
- package/dist/node/path.js +384 -0
- package/dist/node/perf_hooks.js +313 -0
- package/dist/node/process.js +452 -0
- package/dist/node/punycode.js +178 -0
- package/dist/node/querystring.js +934 -0
- package/dist/node/readline/promises.js +71 -0
- package/dist/node/readline.js +56 -0
- package/dist/node/repl.js +44 -0
- package/dist/node/sqlite.js +22 -0
- package/dist/node/stream/consumers.js +47 -0
- package/dist/node/stream/promises.js +6 -0
- package/dist/node/stream/web.js +52 -0
- package/dist/node/stream.js +4323 -0
- package/dist/node/string_decoder.js +276 -0
- package/dist/node/sys.js +6 -0
- package/dist/node/timers/promises.js +71 -0
- package/dist/node/timers.js +133 -0
- package/dist/node/tls.js +122 -0
- package/dist/node/trace_events.js +23 -0
- package/dist/node/tty.js +69 -0
- package/dist/node/url.js +1426 -0
- package/dist/node/util/types.js +1456 -0
- package/dist/node/util.js +4807 -0
- package/dist/node/v8.js +160 -0
- package/dist/node/vm.js +88 -0
- package/dist/node/wasi.js +16 -0
- package/dist/node/worker_threads.js +123 -0
- package/dist/node/zlib.js +1396 -0
- package/dist/node-builtins.d.ts +40 -0
- package/dist/node-builtins.js +74 -0
- package/dist/node-on-page.d.ts +46 -0
- package/dist/node-on-page.js +101 -0
- package/dist/node-platform.d.ts +36 -0
- package/dist/node-platform.js +152 -0
- package/dist/node-rendered.d.ts +21 -0
- package/dist/node-rendered.js +26 -0
- package/dist/node-server.d.ts +46 -0
- package/dist/node-server.js +193 -0
- package/dist/optimizer-cache-key.d.ts +26 -0
- package/dist/optimizer-cache-key.js +73 -0
- package/dist/own-package.d.ts +1 -0
- package/dist/own-package.js +6 -0
- package/dist/page-store.d.ts +33 -0
- package/dist/page-store.js +80 -0
- package/dist/page-timers.d.ts +22 -0
- package/dist/page-timers.js +47 -0
- package/dist/page.d.ts +112 -0
- package/dist/page.js +549 -0
- package/dist/paths.d.ts +13 -0
- package/dist/paths.js +47 -0
- package/dist/plugin.d.ts +22 -0
- package/dist/plugin.js +995 -0
- package/dist/prerender-verdict.d.ts +8 -0
- package/dist/prerender-verdict.js +67 -0
- package/dist/project/context.d.ts +546 -0
- package/dist/project/context.js +111 -0
- package/dist/project/entries.d.ts +42 -0
- package/dist/project/entries.js +189 -0
- package/dist/project/env-worker.d.ts +1 -0
- package/dist/project/env-worker.js +9 -0
- package/dist/project/env.d.ts +36 -0
- package/dist/project/env.js +82 -0
- package/dist/project/layers.d.ts +31 -0
- package/dist/project/layers.js +150 -0
- package/dist/project/loaders.d.ts +71 -0
- package/dist/project/loaders.js +300 -0
- package/dist/project/metadata.d.ts +8 -0
- package/dist/project/metadata.js +34 -0
- package/dist/project/module-exports.d.ts +29 -0
- package/dist/project/module-exports.js +77 -0
- package/dist/project/routes.d.ts +19 -0
- package/dist/project/routes.js +92 -0
- package/dist/project/routing.d.ts +46 -0
- package/dist/project/routing.js +280 -0
- package/dist/project/transform.d.ts +8 -0
- package/dist/project/transform.js +110 -0
- package/dist/project/webpack.d.ts +46 -0
- package/dist/project/webpack.js +160 -0
- package/dist/project.d.ts +264 -0
- package/dist/project.js +58 -0
- package/dist/registry-global.d.ts +5 -0
- package/dist/registry-global.js +5 -0
- package/dist/registry.d.ts +241 -0
- package/dist/registry.js +30 -0
- package/dist/route-chunks.d.ts +13 -0
- package/dist/route-chunks.js +32 -0
- package/dist/route-lookup.d.ts +34 -0
- package/dist/route-lookup.js +207 -0
- package/dist/routes-ahead-shared.d.ts +17 -0
- package/dist/routes-ahead-shared.js +9 -0
- package/dist/routes-ahead.d.ts +10 -0
- package/dist/routes-ahead.js +54 -0
- package/dist/rsc.d.ts +19 -0
- package/dist/rsc.js +171 -0
- package/dist/server-action.d.ts +9 -0
- package/dist/server-action.js +15 -0
- package/dist/server-code.d.ts +176 -0
- package/dist/server-code.js +357 -0
- package/dist/server-in-front.d.ts +37 -0
- package/dist/server-in-front.js +90 -0
- package/dist/server-layers.d.ts +22 -0
- package/dist/server-layers.js +33 -0
- package/dist/setup-browser.d.ts +1 -0
- package/dist/setup-browser.js +8 -0
- package/dist/setup-node.d.ts +1 -0
- package/dist/setup-node.js +6 -0
- package/dist/setup.d.ts +8 -0
- package/dist/setup.js +62 -0
- package/dist/speed-features.d.ts +13 -0
- package/dist/speed-features.js +95 -0
- package/dist/ssr.d.ts +70 -0
- package/dist/ssr.js +480 -0
- package/dist/static-build.d.ts +36 -0
- package/dist/static-build.js +92 -0
- package/dist/storage.d.ts +31 -0
- package/dist/storage.js +94 -0
- package/dist/styles-shared.d.ts +137 -0
- package/dist/styles-shared.js +124 -0
- package/dist/styles.d.ts +102 -0
- package/dist/styles.js +730 -0
- package/dist/stylesheet-versions.d.ts +17 -0
- package/dist/stylesheet-versions.js +43 -0
- package/dist/tester.html +10 -0
- package/dist/use-cache.d.ts +15 -0
- package/dist/use-cache.js +93 -0
- package/dist/vitest-version.d.ts +6 -0
- package/dist/vitest-version.js +12 -0
- package/package.json +125 -4
package/dist/document.js
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import "./styles-shared.js";
|
|
2
|
+
import pageHost from "virtual:vitest-plugin-rsc/page-host";
|
|
3
|
+
import { releaseTimers, runnerTimers } from "@kasperpeulen/vitest-plugin-rsc/internal/timers";
|
|
4
|
+
//#region src/document.ts
|
|
5
|
+
const elements = (of) => [
|
|
6
|
+
of.documentElement,
|
|
7
|
+
of.head,
|
|
8
|
+
of.body
|
|
9
|
+
];
|
|
10
|
+
const attributesOf = (element) => Array.from(element.attributes, ({ name, value }) => [name, value]);
|
|
11
|
+
let unload;
|
|
12
|
+
const keptProperties = /* @__PURE__ */ new WeakMap();
|
|
13
|
+
/**
|
|
14
|
+
* Keeps the properties `keys` of `target`, the document or one of its
|
|
15
|
+
* elements, as the pages are left, until it is called again: the marks of
|
|
16
|
+
* React DOM on the root of an app that renders the pages after its first
|
|
17
|
+
* (`renderAgain()` in client.tsx). Without `keys` they are no longer kept,
|
|
18
|
+
* and the app that kept them removes them.
|
|
19
|
+
*/
|
|
20
|
+
function keepProperties(target, keys) {
|
|
21
|
+
if (keys) keptProperties.set(target, new Set(keys));
|
|
22
|
+
else keptProperties.delete(target);
|
|
23
|
+
}
|
|
24
|
+
const keptNodes = /* @__PURE__ */ new Set();
|
|
25
|
+
let preloads = [];
|
|
26
|
+
let runnerHref;
|
|
27
|
+
/**
|
|
28
|
+
* The URL of the document without the page that is open: the runner's, which
|
|
29
|
+
* the page shows as its own while it is open.
|
|
30
|
+
*/
|
|
31
|
+
function documentUrl() {
|
|
32
|
+
return runnerHref ?? window.location.href;
|
|
33
|
+
}
|
|
34
|
+
const navigation = window.navigation;
|
|
35
|
+
function activate() {
|
|
36
|
+
if (!navigation || !("activation" in navigation)) return () => {};
|
|
37
|
+
const activation = {
|
|
38
|
+
entry: navigation.currentEntry,
|
|
39
|
+
from: null,
|
|
40
|
+
navigationType: "push"
|
|
41
|
+
};
|
|
42
|
+
Object.defineProperty(navigation, "activation", {
|
|
43
|
+
configurable: true,
|
|
44
|
+
enumerable: true,
|
|
45
|
+
get: () => activation
|
|
46
|
+
});
|
|
47
|
+
return () => Reflect.deleteProperty(navigation, "activation");
|
|
48
|
+
}
|
|
49
|
+
function staysDuringPage(node) {
|
|
50
|
+
return node instanceof HTMLScriptElement || node instanceof HTMLStyleElement || isPreload(node);
|
|
51
|
+
}
|
|
52
|
+
function isPreload(node) {
|
|
53
|
+
return node instanceof HTMLLinkElement && (node.relList.contains("modulepreload") || node.relList.contains("preload") && node.as !== "style");
|
|
54
|
+
}
|
|
55
|
+
function isViteStyle(node) {
|
|
56
|
+
return node instanceof HTMLStyleElement && node.hasAttribute("data-vite-dev-id");
|
|
57
|
+
}
|
|
58
|
+
function isGraphStylesheet(node) {
|
|
59
|
+
return node instanceof HTMLLinkElement && node.hasAttribute("data-vitest-plugin-rsc-graph");
|
|
60
|
+
}
|
|
61
|
+
function elementsOf(parent, tag) {
|
|
62
|
+
return Array.from(parent.getElementsByTagName(tag));
|
|
63
|
+
}
|
|
64
|
+
const hasRel = (link, keyword) => link.rel.toLowerCase().split(/[\t\n\f\r ]+/).includes(keyword);
|
|
65
|
+
function stylesheetsOf(parent, url) {
|
|
66
|
+
return elementsOf(parent, "link").filter((link) => hasRel(link, "stylesheet") && !link.relList.contains("alternate") && link.getAttribute("href") && (!link.type || link.type === "text/css") && URL.canParse(link.getAttribute("href"), url) && new URL(link.getAttribute("href"), url).origin === window.location.origin);
|
|
67
|
+
}
|
|
68
|
+
function stylesheetLoaded(link) {
|
|
69
|
+
return new Promise((resolve) => {
|
|
70
|
+
link.addEventListener("load", () => resolve(), { once: true });
|
|
71
|
+
link.addEventListener("error", () => resolve(), { once: true });
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
const globalsOfThePage = [
|
|
75
|
+
"next",
|
|
76
|
+
"nd",
|
|
77
|
+
"_N_E_STYLE_LOAD",
|
|
78
|
+
"__next_set_public_path__",
|
|
79
|
+
"__NEXT_HMR_CB",
|
|
80
|
+
"$RB",
|
|
81
|
+
"$RM",
|
|
82
|
+
"$RR",
|
|
83
|
+
"$RS",
|
|
84
|
+
"$RT",
|
|
85
|
+
"$RV",
|
|
86
|
+
"$RX"
|
|
87
|
+
];
|
|
88
|
+
const deleteGlobalsOfThePage = () => {
|
|
89
|
+
for (const name of globalsOfThePage) Reflect.deleteProperty(window, name);
|
|
90
|
+
};
|
|
91
|
+
const reactScript = /\$R[A-Z]\b/;
|
|
92
|
+
function runInlineScript(code, timers) {
|
|
93
|
+
if (!reactScript.test(code)) {
|
|
94
|
+
(0, eval)(code);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
new Function("setTimeout", "clearTimeout", "requestAnimationFrame", "cancelAnimationFrame", code)(timers.setTimeout, timers.clearTimeout, timers.requestAnimationFrame, timers.cancelAnimationFrame);
|
|
98
|
+
}
|
|
99
|
+
const reactProperty = /^_+react/;
|
|
100
|
+
function forgetReact(root) {
|
|
101
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT);
|
|
102
|
+
for (let node = root; node; node = walker.nextNode()) for (const key of Object.keys(node)) if (reactProperty.test(key)) Reflect.deleteProperty(node, key);
|
|
103
|
+
}
|
|
104
|
+
function setAttributes(element, attributes) {
|
|
105
|
+
for (const { name } of Array.from(element.attributes)) element.removeAttribute(name);
|
|
106
|
+
for (const [name, value] of attributes) element.setAttribute(name, value);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Starts the files of the route of the page that loads next, as the server
|
|
110
|
+
* renders it: `stylesheets` as Next links them, in the CORS mode of
|
|
111
|
+
* `crossOrigin`, and `modules`. By their URLs. They go with that page.
|
|
112
|
+
*/
|
|
113
|
+
function preloadPage({ stylesheets, crossOrigin, modules }) {
|
|
114
|
+
const links = [...stylesheets.map((href) => ({
|
|
115
|
+
href,
|
|
116
|
+
rel: "preload",
|
|
117
|
+
as: "style",
|
|
118
|
+
crossOrigin
|
|
119
|
+
})), ...modules.map((href) => ({
|
|
120
|
+
href,
|
|
121
|
+
rel: "modulepreload",
|
|
122
|
+
as: "",
|
|
123
|
+
crossOrigin: ""
|
|
124
|
+
}))];
|
|
125
|
+
for (const { href, rel, as, crossOrigin } of links) {
|
|
126
|
+
if (preloads.some((link) => link.href === href)) continue;
|
|
127
|
+
const link = document.createElement("link");
|
|
128
|
+
link.rel = rel;
|
|
129
|
+
if (as) link.as = as;
|
|
130
|
+
if (crossOrigin !== void 0) link.crossOrigin = crossOrigin;
|
|
131
|
+
link.href = href;
|
|
132
|
+
document.head.append(link);
|
|
133
|
+
preloads.push(link);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Replaces the page in this document with the one the server sent as `html`:
|
|
138
|
+
* its `<head>` first, the rest once the stylesheets of the `<head>` have
|
|
139
|
+
* loaded, and runs its inline scripts in document order once the stylesheets
|
|
140
|
+
* of the rest have too. Resolves then, and without running them for a page
|
|
141
|
+
* that was left in the meantime.
|
|
142
|
+
*
|
|
143
|
+
* The page is there in full before the app starts, so the document has loaded
|
|
144
|
+
* by the time Next's client looks: it reads the Flight payload that Next's
|
|
145
|
+
* inline scripts left in `self.__next_f`, and hydrates.
|
|
146
|
+
*
|
|
147
|
+
* With a `container`, the page is the one of a node, which renders no
|
|
148
|
+
* `<html>` or `<body>`, and what is in the document stays the test's. What
|
|
149
|
+
* the HTML parser puts in `<body>` goes in the container: the node, with the
|
|
150
|
+
* scripts it renders, and after it the scripts of Next and React.
|
|
151
|
+
*
|
|
152
|
+
* The page takes the entry of the history that the document is at, or with
|
|
153
|
+
* `after` gets one of its own, after that entry. With `inKeptApp`, leaving
|
|
154
|
+
* the page leaves what the app added to the `<head>`: see `unloadKeptApp()`.
|
|
155
|
+
* React's inline scripts get timers of the page's own, which leaving the
|
|
156
|
+
* page clears.
|
|
157
|
+
*
|
|
158
|
+
* Returns what takes React DOM's properties off the nodes of this page,
|
|
159
|
+
* before its root unmounts: React takes the nodes out of the document as it
|
|
160
|
+
* does, and leaves its fiber on a text node. A node that outlives the page
|
|
161
|
+
* then keeps no fiber of it: the one that an assertion of the test holds
|
|
162
|
+
* until it ends, or the one under the pointer. Once the page is left, it
|
|
163
|
+
* does nothing: leaving took them off already. Nothing for a page of a kept
|
|
164
|
+
* app, whose root outlives the page.
|
|
165
|
+
*/
|
|
166
|
+
async function loadDocument(html, url, container, after, inKeptApp = false) {
|
|
167
|
+
leaveDocument();
|
|
168
|
+
const ownPreloads = new Set(preloads);
|
|
169
|
+
preloads = [];
|
|
170
|
+
const runnerUrl = window.location.href;
|
|
171
|
+
runnerHref = runnerUrl;
|
|
172
|
+
const runnerBody = document.body;
|
|
173
|
+
const runnerAttributes = elements(document).map(attributesOf);
|
|
174
|
+
const reactTargets = [
|
|
175
|
+
document,
|
|
176
|
+
document.documentElement,
|
|
177
|
+
document.head
|
|
178
|
+
];
|
|
179
|
+
if (container) reactTargets.push(container);
|
|
180
|
+
const runnerProperties = reactTargets.map((target) => new Set(Reflect.ownKeys(target)));
|
|
181
|
+
const runnerAdopted = Array.from(document.adoptedStyleSheets);
|
|
182
|
+
const runnerScripts = new Set(document.querySelectorAll("script"));
|
|
183
|
+
const before = new Set([...document.head.childNodes, ...runnerBody.childNodes].filter((node) => !ownPreloads.has(node) && !keptNodes.has(node)));
|
|
184
|
+
const brought = new Set(ownPreloads);
|
|
185
|
+
const parked = [];
|
|
186
|
+
const graphParked = /* @__PURE__ */ new Set();
|
|
187
|
+
const switchedOff = [];
|
|
188
|
+
const pageBody = document.createElement("body");
|
|
189
|
+
let leaveNow;
|
|
190
|
+
const left = new Promise((resolve) => leaveNow = resolve);
|
|
191
|
+
let deactivate = () => {};
|
|
192
|
+
const pageNodes = () => [...container ? Array.from(container.childNodes) : [], ...[document.head, pageBody].flatMap((parent) => Array.from(parent.childNodes).filter((node) => !before.has(node) && !isViteStyle(node) && !isGraphStylesheet(node)))];
|
|
193
|
+
const scriptTimers = runnerTimers(() => unload !== leave);
|
|
194
|
+
const leave = () => {
|
|
195
|
+
try {
|
|
196
|
+
leaveNow();
|
|
197
|
+
if (!inKeptApp) pageNodes().forEach(forgetReact);
|
|
198
|
+
container?.replaceChildren();
|
|
199
|
+
for (const parent of [document.head, pageBody]) for (const node of Array.from(parent.childNodes)) {
|
|
200
|
+
if (before.has(node) || isViteStyle(node) || isGraphStylesheet(node)) continue;
|
|
201
|
+
if (inKeptApp && parent === document.head && !brought.has(node)) keptNodes.add(node);
|
|
202
|
+
else node.remove();
|
|
203
|
+
}
|
|
204
|
+
} finally {
|
|
205
|
+
runnerHref = void 0;
|
|
206
|
+
deactivate();
|
|
207
|
+
if (window.location.href !== runnerUrl) window.history.replaceState(null, "", runnerUrl);
|
|
208
|
+
}
|
|
209
|
+
document.head.append(...parked.filter((node) => !graphParked.has(node) || isGraphStylesheet(node)));
|
|
210
|
+
for (const [style, media] of switchedOff) if (media === null) style.removeAttribute("media");
|
|
211
|
+
else style.media = media;
|
|
212
|
+
runnerBody.append(...pageBody.childNodes);
|
|
213
|
+
pageBody.replaceWith(runnerBody);
|
|
214
|
+
elements(document).forEach((element, index) => setAttributes(element, runnerAttributes[index]));
|
|
215
|
+
document.adoptedStyleSheets = runnerAdopted;
|
|
216
|
+
reactTargets.forEach((target, index) => {
|
|
217
|
+
for (const key of Reflect.ownKeys(target)) {
|
|
218
|
+
if (runnerProperties[index].has(key) || keptProperties.get(target)?.has(key)) continue;
|
|
219
|
+
Reflect.deleteProperty(target, key);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
delete self.__next_f;
|
|
223
|
+
delete self.__next_s;
|
|
224
|
+
if (!inKeptApp) deleteGlobalsOfThePage();
|
|
225
|
+
releaseTimers(scriptTimers);
|
|
226
|
+
};
|
|
227
|
+
unload = leave;
|
|
228
|
+
const forget = () => {
|
|
229
|
+
if (!inKeptApp && unload === leave) pageNodes().forEach(forgetReact);
|
|
230
|
+
};
|
|
231
|
+
const page = new DOMParser().parseFromString(html, "text/html");
|
|
232
|
+
for (const redirect of elementsOf(page, "meta")) if (redirect.id === "__next-page-redirect") redirect.removeAttribute("http-equiv");
|
|
233
|
+
const urlOf = (element, name) => {
|
|
234
|
+
const value = element.getAttribute(name);
|
|
235
|
+
return value !== null && URL.canParse(value, url) ? new URL(value, url).href : void 0;
|
|
236
|
+
};
|
|
237
|
+
const sources = new Set(elementsOf(page, "script").map((script) => urlOf(script, "src")));
|
|
238
|
+
sources.delete(void 0);
|
|
239
|
+
for (const link of elementsOf(page, "link")) if (link.rel.toLowerCase() === "preload" && link.getAttribute("as") === "script") {
|
|
240
|
+
if (sources.has(urlOf(link, "href"))) link.remove();
|
|
241
|
+
}
|
|
242
|
+
const stylesheetsOfHead = stylesheetsOf(page.head, url);
|
|
243
|
+
const stylesheetsOfBody = stylesheetsOf(page.body, url);
|
|
244
|
+
const loaded = (stylesheets) => Promise.race([pageHost.loadsStylesheets ? Promise.all(stylesheets.filter((link) => !link.disabled).map(stylesheetLoaded)) : void 0, left]);
|
|
245
|
+
if (after) {
|
|
246
|
+
window.history.replaceState(after.state, "", after.url);
|
|
247
|
+
window.history.pushState(null, "", url);
|
|
248
|
+
} else window.history.replaceState(null, "", url);
|
|
249
|
+
deactivate = activate();
|
|
250
|
+
const head = Array.from(page.head.childNodes);
|
|
251
|
+
for (const node of head) brought.add(node);
|
|
252
|
+
document.head.append(...head);
|
|
253
|
+
await loaded(stylesheetsOfHead);
|
|
254
|
+
if (unload !== leave) return forget;
|
|
255
|
+
for (const node of runnerBody.childNodes) before.add(node);
|
|
256
|
+
for (const node of container ? [] : document.head.childNodes) {
|
|
257
|
+
if (!before.has(node)) continue;
|
|
258
|
+
if (isViteStyle(node)) switchedOff.push([node, node.getAttribute("media")]);
|
|
259
|
+
else if (!staysDuringPage(node)) parked.push(node);
|
|
260
|
+
if (isGraphStylesheet(node)) graphParked.add(node);
|
|
261
|
+
}
|
|
262
|
+
for (const node of parked) document.head.removeChild(node);
|
|
263
|
+
for (const [style] of switchedOff) style.media = "not all";
|
|
264
|
+
const staying = Array.from(runnerBody.childNodes).filter((node) => container || staysDuringPage(node));
|
|
265
|
+
setAttributes(pageBody, attributesOf(runnerBody));
|
|
266
|
+
document.documentElement.replaceChild(pageBody, runnerBody);
|
|
267
|
+
pageBody.append(...staying);
|
|
268
|
+
if (container) container.append(...page.body.childNodes);
|
|
269
|
+
else {
|
|
270
|
+
elements(page).forEach((element, index) => setAttributes(elements(document)[index], attributesOf(element)));
|
|
271
|
+
pageBody.append(...page.body.childNodes);
|
|
272
|
+
}
|
|
273
|
+
await loaded(stylesheetsOfBody);
|
|
274
|
+
if (unload !== leave) return forget;
|
|
275
|
+
for (const script of document.querySelectorAll("script")) {
|
|
276
|
+
if (runnerScripts.has(script) || script.src) continue;
|
|
277
|
+
if (!script.type || script.type === "text/javascript" || script.type === "module") try {
|
|
278
|
+
runInlineScript(script.textContent ?? "", scriptTimers);
|
|
279
|
+
} catch (error) {
|
|
280
|
+
reportError(error);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return forget;
|
|
284
|
+
}
|
|
285
|
+
let queueStreamedContent;
|
|
286
|
+
/** `self.$RC` of a page. */
|
|
287
|
+
const streamedContentQueue = {
|
|
288
|
+
configurable: true,
|
|
289
|
+
set: (queue) => queueStreamedContent = queue,
|
|
290
|
+
get: () => queueStreamedContent && ((...args) => {
|
|
291
|
+
queueStreamedContent(...args);
|
|
292
|
+
const { $RB: queued, $RV: reveal } = self;
|
|
293
|
+
try {
|
|
294
|
+
if (queued?.length && reveal) reveal(queued);
|
|
295
|
+
} catch (error) {
|
|
296
|
+
reportError(error);
|
|
297
|
+
}
|
|
298
|
+
})
|
|
299
|
+
};
|
|
300
|
+
function leaveDocument() {
|
|
301
|
+
const leave = unload;
|
|
302
|
+
unload = void 0;
|
|
303
|
+
leave?.();
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Takes back what the code of the kept app added to the `<head>` as its pages
|
|
307
|
+
* were open, once the app is left: see `loadDocument()`. With `withGlobals`,
|
|
308
|
+
* also the globals of Next and React on `window` that point into it.
|
|
309
|
+
*/
|
|
310
|
+
function unloadKeptApp(withGlobals = true) {
|
|
311
|
+
for (const node of keptNodes) if (node.parentNode === document.head) node.remove();
|
|
312
|
+
keptNodes.clear();
|
|
313
|
+
if (withGlobals) deleteGlobalsOfThePage();
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Leaves the page, and the one that was loading: the document is as it was
|
|
317
|
+
* before the page, but for what a kept app keeps (`unloadKeptApp()`).
|
|
318
|
+
*/
|
|
319
|
+
function unloadDocument() {
|
|
320
|
+
try {
|
|
321
|
+
leaveDocument();
|
|
322
|
+
} finally {
|
|
323
|
+
for (const link of preloads) link.remove();
|
|
324
|
+
preloads = [];
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
//#endregion
|
|
328
|
+
export { documentUrl, keepProperties, loadDocument, preloadPage, streamedContentQueue, unloadDocument, unloadKeptApp };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/downloads.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The name a browser saves the answer to a navigation as, or none when it
|
|
4
|
+
* shows the answer. `requested` is the navigation's `downloadRequest`: the
|
|
5
|
+
* `download` attribute of a link, `""` without a value.
|
|
6
|
+
*/
|
|
7
|
+
declare function downloadName(response: Response, requested: string | null): string | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Hands the answer to the browser as a download, as `name`: the browser
|
|
10
|
+
* saves the body of a Blob URL that an `<a download>` links, and the URL goes
|
|
11
|
+
* once it has. An answer that is not ok is no file, as in a browser.
|
|
12
|
+
*/
|
|
13
|
+
declare function download(response: Response, name: string, signal: AbortSignal): Promise<void>;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { download, downloadName };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
//#region src/downloads.ts
|
|
2
|
+
/**
|
|
3
|
+
* The name a browser saves the answer to a navigation as, or none when it
|
|
4
|
+
* shows the answer. `requested` is the navigation's `downloadRequest`: the
|
|
5
|
+
* `download` attribute of a link, `""` without a value.
|
|
6
|
+
*/
|
|
7
|
+
function downloadName(response, requested) {
|
|
8
|
+
const disposition = response.headers.get("content-disposition") ?? "";
|
|
9
|
+
const type = /^\s*([^\s;=]*)\s*(?:;|$)/.exec(disposition)?.[1]?.toLowerCase();
|
|
10
|
+
if (requested === null && (!type || type === "inline")) return void 0;
|
|
11
|
+
const fromUrl = decode(percentDecoded(new URL(response.url).pathname.split("/").pop()), "utf-8");
|
|
12
|
+
return filenameOf(disposition) || requested || fromUrl || "download";
|
|
13
|
+
}
|
|
14
|
+
function filenameOf(disposition) {
|
|
15
|
+
const parameters = /* @__PURE__ */ new Map();
|
|
16
|
+
for (const [, name, value] of disposition.matchAll(/;\s*([^\s=;]+)\s*=\s*("(?:[^"\\]|\\.)*"|[^;]*)/g)) {
|
|
17
|
+
const unquoted = value.startsWith("\"") ? value.slice(1, -1).replace(/\\(.)/g, "$1") : value;
|
|
18
|
+
if (!parameters.has(name.toLowerCase())) parameters.set(name.toLowerCase(), unquoted.trim());
|
|
19
|
+
}
|
|
20
|
+
const extended = /^([\w!#$%&+^`{}~-]+)'[^']*'(.*)$/.exec(parameters.get("filename*") ?? "");
|
|
21
|
+
if (extended) {
|
|
22
|
+
const decoded = decode(percentDecoded(extended[2]), extended[1]);
|
|
23
|
+
if (decoded) return decoded;
|
|
24
|
+
}
|
|
25
|
+
const plain = parameters.get("filename");
|
|
26
|
+
if (!plain) return void 0;
|
|
27
|
+
const text = decode(Uint8Array.from(plain, (char) => char.charCodeAt(0) & 255), "utf-8") ?? plain;
|
|
28
|
+
return /^[\x20-\x7e]*%[\da-f]{2}[\x20-\x7e]*$/i.test(text) ? decode(percentDecoded(text), "utf-8") ?? text : text;
|
|
29
|
+
}
|
|
30
|
+
function percentDecoded(text) {
|
|
31
|
+
const bytes = [];
|
|
32
|
+
for (let at = 0; at < text.length; at++) {
|
|
33
|
+
const escaped = /^%([\da-f]{2})/i.exec(text.slice(at, at + 3));
|
|
34
|
+
if (escaped) {
|
|
35
|
+
bytes.push(parseInt(escaped[1], 16));
|
|
36
|
+
at += 2;
|
|
37
|
+
} else bytes.push(text.charCodeAt(at) & 255);
|
|
38
|
+
}
|
|
39
|
+
return Uint8Array.from(bytes);
|
|
40
|
+
}
|
|
41
|
+
function decode(bytes, charset) {
|
|
42
|
+
try {
|
|
43
|
+
return new TextDecoder(charset, { fatal: true }).decode(bytes);
|
|
44
|
+
} catch {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Hands the answer to the browser as a download, as `name`: the browser
|
|
50
|
+
* saves the body of a Blob URL that an `<a download>` links, and the URL goes
|
|
51
|
+
* once it has. An answer that is not ok is no file, as in a browser.
|
|
52
|
+
*/
|
|
53
|
+
async function download(response, name, signal) {
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
await response.body?.cancel();
|
|
56
|
+
throw new Error(`vitest-plugin-rsc: the download of ${response.url} failed: it responded with ${response.status}. A browser saves no file for it.`);
|
|
57
|
+
}
|
|
58
|
+
const blob = await response.blob();
|
|
59
|
+
signal.throwIfAborted();
|
|
60
|
+
const url = URL.createObjectURL(blob);
|
|
61
|
+
try {
|
|
62
|
+
const link = document.createElement("a");
|
|
63
|
+
link.href = url;
|
|
64
|
+
link.download = name;
|
|
65
|
+
link.click();
|
|
66
|
+
} finally {
|
|
67
|
+
URL.revokeObjectURL(url);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
export { download, downloadName };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
|
|
3
|
+
//#region src/esm-require.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The plugin of the optimizer that makes `__toCommonJS` of Rolldown's runtime
|
|
6
|
+
* return one object per module. A runtime that does not have it as above is
|
|
7
|
+
* left as it is.
|
|
8
|
+
*/
|
|
9
|
+
declare function esmRequirePlugin(): Plugin;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { esmRequirePlugin };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/esm-require.ts
|
|
2
|
+
const declaration = /^(?:export )?var __toCommonJS = /m;
|
|
3
|
+
const copy = /__copyProps\(\s*__defProp\(\s*\{\s*\}\s*,\s*(["'])__esModule\1\s*,\s*\{\s*value:\s*true\s*\}\s*\)\s*,\s*mod\s*\)/y;
|
|
4
|
+
/**
|
|
5
|
+
* The plugin of the optimizer that makes `__toCommonJS` of Rolldown's runtime
|
|
6
|
+
* return one object per module. A runtime that does not have it as above is
|
|
7
|
+
* left as it is.
|
|
8
|
+
*/
|
|
9
|
+
function esmRequirePlugin() {
|
|
10
|
+
return {
|
|
11
|
+
name: "vitest-plugin-rsc:esm-require",
|
|
12
|
+
transform: {
|
|
13
|
+
filter: { id: /rolldown\/runtime\.js$/ },
|
|
14
|
+
handler(code) {
|
|
15
|
+
const start = code.search(declaration);
|
|
16
|
+
if (start === -1) return;
|
|
17
|
+
const end = code.indexOf(";", start);
|
|
18
|
+
const at = code.indexOf("__copyProps(", start);
|
|
19
|
+
copy.lastIndex = at;
|
|
20
|
+
const copied = at !== -1 && at < end ? copy.exec(code)?.[0] : void 0;
|
|
21
|
+
if (!copied) return;
|
|
22
|
+
const cached = `(__toCommonJSOf.get(mod) ?? __toCommonJSOf.set(mod, ${copied}).get(mod))`;
|
|
23
|
+
return {
|
|
24
|
+
code: `${code.slice(0, start)}var __toCommonJSOf = new WeakMap();\n${code.slice(start, at)}${cached}${code.slice(at + copied.length)}`,
|
|
25
|
+
map: null
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { esmRequirePlugin };
|