@noego/wood 0.6.2 → 0.7.1
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 +7 -0
- package/dist/browser-test-setup.cjs +29 -0
- package/dist/browser-test-setup.cjs.map +1 -0
- package/dist/browser-test-setup.d.cts +8 -0
- package/dist/browser-test-setup.d.ts +8 -0
- package/dist/browser-test-setup.js +9 -0
- package/dist/browser-test-setup.js.map +1 -0
- package/dist/client/global_polyfill.d.cts +1 -0
- package/dist/client/global_polyfill.d.ts +1 -0
- package/dist/client/index.cjs +7 -0
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +7 -4
- package/dist/client/index.d.ts +7 -4
- package/dist/client/index.js +6 -1
- package/dist/client/index.js.map +1 -1
- package/dist/codegen/renderer_app_generator.cjs +97 -24
- package/dist/codegen/renderer_app_generator.cjs.map +1 -1
- package/dist/codegen/renderer_app_generator.js +97 -24
- package/dist/codegen/renderer_app_generator.js.map +1 -1
- package/dist/codegen/type_generator.cjs +9 -0
- package/dist/codegen/type_generator.cjs.map +1 -1
- package/dist/codegen/type_generator.js +9 -0
- package/dist/codegen/type_generator.js.map +1 -1
- package/dist/config/config_parser.cjs +10 -0
- package/dist/config/config_parser.cjs.map +1 -1
- package/dist/config/config_parser.js +10 -0
- package/dist/config/config_parser.js.map +1 -1
- package/dist/fetch.cjs +38 -0
- package/dist/fetch.cjs.map +1 -0
- package/dist/fetch.d.cts +7 -0
- package/dist/fetch.d.ts +7 -0
- package/dist/fetch.js +12 -0
- package/dist/fetch.js.map +1 -0
- package/dist/frontend/frontend_page.cjs +3 -3
- package/dist/frontend/frontend_page.cjs.map +1 -1
- package/dist/frontend/frontend_page.d.cts +1 -1
- package/dist/frontend/frontend_page.d.ts +1 -1
- package/dist/frontend/frontend_page.js +3 -3
- package/dist/frontend/frontend_page.js.map +1 -1
- package/dist/frontend/frontend_surface.cjs +31 -17
- package/dist/frontend/frontend_surface.cjs.map +1 -1
- package/dist/frontend/frontend_surface.d.cts +12 -2
- package/dist/frontend/frontend_surface.d.ts +12 -2
- package/dist/frontend/frontend_surface.js +37 -17
- package/dist/frontend/frontend_surface.js.map +1 -1
- package/dist/frontend/index.d.cts +2 -0
- package/dist/frontend/index.d.ts +2 -0
- package/dist/index.cjs +5 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/loader/index.cjs +19 -2
- package/dist/loader/index.cjs.map +1 -1
- package/dist/loader/index.d.cts +1 -0
- package/dist/loader/index.d.ts +1 -0
- package/dist/loader/index.js +19 -1
- package/dist/loader/index.js.map +1 -1
- package/dist/loader/loader_orchestration.cjs +82 -0
- package/dist/loader/loader_orchestration.cjs.map +1 -0
- package/dist/loader/loader_orchestration.d.cts +66 -0
- package/dist/loader/loader_orchestration.d.ts +66 -0
- package/dist/loader/loader_orchestration.js +51 -0
- package/dist/loader/loader_orchestration.js.map +1 -0
- package/dist/loader/loader_runner.cjs +46 -41
- package/dist/loader/loader_runner.cjs.map +1 -1
- package/dist/loader/loader_runner.d.cts +12 -6
- package/dist/loader/loader_runner.d.ts +12 -6
- package/dist/loader/loader_runner.js +50 -41
- package/dist/loader/loader_runner.js.map +1 -1
- package/dist/native_browser.types-BY2daUOS.d.ts +189 -0
- package/dist/native_browser.types-vWXtE4rM.d.cts +189 -0
- package/dist/navigation/index.cjs +15 -2
- package/dist/navigation/index.cjs.map +1 -1
- package/dist/navigation/index.d.cts +2 -0
- package/dist/navigation/index.d.ts +2 -0
- package/dist/navigation/index.js +8 -1
- package/dist/navigation/index.js.map +1 -1
- package/dist/runtime/get_container.cjs +2 -0
- package/dist/runtime/get_container.cjs.map +1 -1
- package/dist/runtime/get_container.js +2 -0
- package/dist/runtime/get_container.js.map +1 -1
- package/dist/runtime/index.cjs +5 -0
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +2 -0
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/index.js +3 -0
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/runtime_capabilities.cjs +35 -0
- package/dist/runtime/runtime_capabilities.cjs.map +1 -0
- package/dist/runtime/runtime_capabilities.d.cts +6 -0
- package/dist/runtime/runtime_capabilities.d.ts +6 -0
- package/dist/runtime/runtime_capabilities.js +11 -0
- package/dist/runtime/runtime_capabilities.js.map +1 -0
- package/dist/runtime/runtime_module.cjs +2 -0
- package/dist/runtime/runtime_module.cjs.map +1 -1
- package/dist/runtime/runtime_module.js +2 -0
- package/dist/runtime/runtime_module.js.map +1 -1
- package/dist/test-wood.cjs +150 -0
- package/dist/test-wood.cjs.map +1 -0
- package/dist/test-wood.d.cts +62 -0
- package/dist/test-wood.d.ts +62 -0
- package/dist/test-wood.js +115 -0
- package/dist/test-wood.js.map +1 -0
- package/dist/testing/browser.cjs +92 -163
- package/dist/testing/browser.cjs.map +1 -1
- package/dist/testing/browser.d.cts +14 -13
- package/dist/testing/browser.d.ts +14 -13
- package/dist/testing/browser.js +88 -162
- package/dist/testing/browser.js.map +1 -1
- package/dist/testing/create_controller_harness.d.cts +2 -1
- package/dist/testing/create_controller_harness.d.ts +2 -1
- package/dist/testing/create_router_bridge.cjs +19 -15
- package/dist/testing/create_router_bridge.cjs.map +1 -1
- package/dist/testing/create_router_bridge.d.cts +8 -1
- package/dist/testing/create_router_bridge.d.ts +8 -1
- package/dist/testing/create_router_bridge.js +18 -15
- package/dist/testing/create_router_bridge.js.map +1 -1
- package/dist/testing/index.cjs +12 -4
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +11 -5
- package/dist/testing/index.d.ts +11 -5
- package/dist/testing/index.js +9 -3
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/native_browser/browser_pool.cjs +31 -0
- package/dist/testing/native_browser/browser_pool.cjs.map +1 -0
- package/dist/testing/native_browser/browser_pool.d.cts +1 -0
- package/dist/testing/native_browser/browser_pool.d.ts +1 -0
- package/dist/testing/native_browser/browser_pool.js +6 -0
- package/dist/testing/native_browser/browser_pool.js.map +1 -0
- package/dist/testing/native_browser/happy_dom_tab.cjs +107 -0
- package/dist/testing/native_browser/happy_dom_tab.cjs.map +1 -0
- package/dist/testing/native_browser/happy_dom_tab.d.cts +35 -0
- package/dist/testing/native_browser/happy_dom_tab.d.ts +35 -0
- package/dist/testing/native_browser/happy_dom_tab.js +73 -0
- package/dist/testing/native_browser/happy_dom_tab.js.map +1 -0
- package/dist/testing/native_browser/happy_dom_transfer.cjs +29 -0
- package/dist/testing/native_browser/happy_dom_transfer.cjs.map +1 -0
- package/dist/testing/native_browser/happy_dom_transfer.d.cts +1 -0
- package/dist/testing/native_browser/happy_dom_transfer.d.ts +1 -0
- package/dist/testing/native_browser/happy_dom_transfer.js +5 -0
- package/dist/testing/native_browser/happy_dom_transfer.js.map +1 -0
- package/dist/testing/native_browser/host_transport.cjs +89 -0
- package/dist/testing/native_browser/host_transport.cjs.map +1 -0
- package/dist/testing/native_browser/host_transport.d.cts +44 -0
- package/dist/testing/native_browser/host_transport.d.ts +44 -0
- package/dist/testing/native_browser/host_transport.js +65 -0
- package/dist/testing/native_browser/host_transport.js.map +1 -0
- package/dist/testing/native_browser/native_browser.types.cjs +17 -0
- package/dist/testing/native_browser/native_browser.types.cjs.map +1 -0
- package/dist/testing/native_browser/native_browser.types.d.cts +31 -0
- package/dist/testing/native_browser/native_browser.types.d.ts +31 -0
- package/dist/testing/native_browser/native_browser.types.js +1 -0
- package/dist/testing/native_browser/native_browser.types.js.map +1 -0
- package/dist/testing/native_browser/native_browser_environment.cjs +143 -0
- package/dist/testing/native_browser/native_browser_environment.cjs.map +1 -0
- package/dist/testing/native_browser/native_browser_environment.d.cts +36 -0
- package/dist/testing/native_browser/native_browser_environment.d.ts +36 -0
- package/dist/testing/native_browser/native_browser_environment.js +109 -0
- package/dist/testing/native_browser/native_browser_environment.js.map +1 -0
- package/dist/testing/native_browser/native_browser_lifecycle.cjs +31 -0
- package/dist/testing/native_browser/native_browser_lifecycle.cjs.map +1 -0
- package/dist/testing/native_browser/native_browser_lifecycle.d.cts +1 -0
- package/dist/testing/native_browser/native_browser_lifecycle.d.ts +1 -0
- package/dist/testing/native_browser/native_browser_lifecycle.js +6 -0
- package/dist/testing/native_browser/native_browser_lifecycle.js.map +1 -0
- package/dist/testing/native_browser/playwright_tab.cjs +124 -0
- package/dist/testing/native_browser/playwright_tab.cjs.map +1 -0
- package/dist/testing/native_browser/playwright_tab.d.cts +35 -0
- package/dist/testing/native_browser/playwright_tab.d.ts +35 -0
- package/dist/testing/native_browser/playwright_tab.js +100 -0
- package/dist/testing/native_browser/playwright_tab.js.map +1 -0
- package/dist/testing/native_browser/renderer_compilation.cjs +149 -0
- package/dist/testing/native_browser/renderer_compilation.cjs.map +1 -0
- package/dist/testing/native_browser/renderer_compilation.d.cts +35 -0
- package/dist/testing/native_browser/renderer_compilation.d.ts +35 -0
- package/dist/testing/native_browser/renderer_compilation.js +115 -0
- package/dist/testing/native_browser/renderer_compilation.js.map +1 -0
- package/dist/testing/native_browser/renderer_entry.cjs +148 -0
- package/dist/testing/native_browser/renderer_entry.cjs.map +1 -0
- package/dist/testing/native_browser/renderer_entry.d.cts +13 -0
- package/dist/testing/native_browser/renderer_entry.d.ts +13 -0
- package/dist/testing/native_browser/renderer_entry.js +114 -0
- package/dist/testing/native_browser/renderer_entry.js.map +1 -0
- package/dist/testing/registration_only_root.cjs +61 -5
- package/dist/testing/registration_only_root.cjs.map +1 -1
- package/dist/testing/registration_only_root.d.cts +25 -4
- package/dist/testing/registration_only_root.d.ts +25 -4
- package/dist/testing/registration_only_root.js +60 -5
- package/dist/testing/registration_only_root.js.map +1 -1
- package/dist/testing/runner_importer.cjs +75 -0
- package/dist/testing/runner_importer.cjs.map +1 -0
- package/dist/testing/runner_importer.d.cts +8 -0
- package/dist/testing/runner_importer.d.ts +8 -0
- package/dist/testing/runner_importer.js +41 -0
- package/dist/testing/runner_importer.js.map +1 -0
- package/dist/testing/test_wood_config.cjs +407 -273
- package/dist/testing/test_wood_config.cjs.map +1 -1
- package/dist/testing/test_wood_config.d.cts +18 -123
- package/dist/testing/test_wood_config.d.ts +18 -123
- package/dist/testing/test_wood_config.js +416 -271
- package/dist/testing/test_wood_config.js.map +1 -1
- package/dist/testing/wood_config_source.cjs +12 -0
- package/dist/testing/wood_config_source.cjs.map +1 -1
- package/dist/testing/wood_config_source.d.cts +10 -0
- package/dist/testing/wood_config_source.d.ts +10 -0
- package/dist/testing/wood_config_source.js +12 -0
- package/dist/testing/wood_config_source.js.map +1 -1
- package/dist/testing/wood_env_renderer.cjs +31 -4
- package/dist/testing/wood_env_renderer.cjs.map +1 -1
- package/dist/testing/wood_env_renderer.d.cts +14 -1
- package/dist/testing/wood_env_renderer.d.ts +14 -1
- package/dist/testing/wood_env_renderer.js +31 -4
- package/dist/testing/wood_env_renderer.js.map +1 -1
- package/dist/testing/wood_lazy_runtime.cjs +109 -0
- package/dist/testing/wood_lazy_runtime.cjs.map +1 -0
- package/dist/testing/wood_lazy_runtime.d.cts +36 -0
- package/dist/testing/wood_lazy_runtime.d.ts +36 -0
- package/dist/testing/wood_lazy_runtime.js +84 -0
- package/dist/testing/wood_lazy_runtime.js.map +1 -0
- package/dist/testing/wood_test_selection.cjs +34 -55
- package/dist/testing/wood_test_selection.cjs.map +1 -1
- package/dist/testing/wood_test_selection.d.cts +18 -24
- package/dist/testing/wood_test_selection.d.ts +18 -24
- package/dist/testing/wood_test_selection.js +30 -54
- package/dist/testing/wood_test_selection.js.map +1 -1
- package/dist/testing-api.cjs +17 -0
- package/dist/testing-api.cjs.map +1 -0
- package/dist/testing-api.d.cts +18 -0
- package/dist/testing-api.d.ts +18 -0
- package/dist/testing-api.js +1 -0
- package/dist/testing-api.js.map +1 -0
- package/dist/types/config.cjs.map +1 -1
- package/dist/types/config.d.cts +4 -0
- package/dist/types/config.d.ts +4 -0
- package/docs/native-browser-testing.md +164 -0
- package/package.json +31 -5
- package/src/components/NavigationShell.browser.test.ts +10 -10
- package/src/components/NavigationShell.cleanup.browser.test.ts +57 -0
- package/src/components/NavigationShell.scopes.browser.test.ts +5 -5
- package/src/components/NavigationShell.svelte +50 -24
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BrowserContext } from 'playwright';
|
|
2
|
+
import { h as NativeBrowserInputs, i as NativeRendererBundle, j as NativeRendererRoute, k as NativeBrowserTab } from '../../native_browser.types-vWXtE4rM.cjs';
|
|
3
|
+
import '@noego/testing/fetch';
|
|
4
|
+
import 'happy-dom';
|
|
5
|
+
import '../wood_config_source.cjs';
|
|
6
|
+
import '../../types/config.cjs';
|
|
7
|
+
import '../../types/operations.cjs';
|
|
8
|
+
import '../../types/views.cjs';
|
|
9
|
+
import '../create_router_bridge.cjs';
|
|
10
|
+
import '../../router/wood_router.cjs';
|
|
11
|
+
import '../../types/context.cjs';
|
|
12
|
+
import '../../validation/schema_validator.cjs';
|
|
13
|
+
import '../../middleware/middleware_resolver.cjs';
|
|
14
|
+
import '../../controller/controller_resolver.cjs';
|
|
15
|
+
import '../../testing-api.cjs';
|
|
16
|
+
import '@noego/ioc';
|
|
17
|
+
import '@noego/testing';
|
|
18
|
+
import '../../frontend/frontend_surface.cjs';
|
|
19
|
+
import '../../navigation/index.cjs';
|
|
20
|
+
import '../../navigation/layout_preservation.cjs';
|
|
21
|
+
import '../../navigation/automation_introspection.cjs';
|
|
22
|
+
import '../../loader/loader_orchestration.cjs';
|
|
23
|
+
import '../../frontend/page_catalog.cjs';
|
|
24
|
+
import '../../frontend/work_registry.cjs';
|
|
25
|
+
import '../../frontend/frontend_lifecycle.cjs';
|
|
26
|
+
import '../../frontend/frontend_page.cjs';
|
|
27
|
+
import '../wood_test_selection.cjs';
|
|
28
|
+
import '../wood_env_renderer.cjs';
|
|
29
|
+
import '../wood_dom_animation.cjs';
|
|
30
|
+
import '../registration_only_root.cjs';
|
|
31
|
+
import '../test_wood.cjs';
|
|
32
|
+
|
|
33
|
+
declare function openPlaywrightTab(inputs: NativeBrowserInputs, context: BrowserContext, bundle: NativeRendererBundle, route: NativeRendererRoute): Promise<NativeBrowserTab>;
|
|
34
|
+
|
|
35
|
+
export { openPlaywrightTab };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BrowserContext } from 'playwright';
|
|
2
|
+
import { h as NativeBrowserInputs, i as NativeRendererBundle, j as NativeRendererRoute, k as NativeBrowserTab } from '../../native_browser.types-BY2daUOS.js';
|
|
3
|
+
import '@noego/testing/fetch';
|
|
4
|
+
import 'happy-dom';
|
|
5
|
+
import '../wood_config_source.js';
|
|
6
|
+
import '../../types/config.js';
|
|
7
|
+
import '../../types/operations.js';
|
|
8
|
+
import '../../types/views.js';
|
|
9
|
+
import '../create_router_bridge.js';
|
|
10
|
+
import '../../router/wood_router.js';
|
|
11
|
+
import '../../types/context.js';
|
|
12
|
+
import '../../validation/schema_validator.js';
|
|
13
|
+
import '../../middleware/middleware_resolver.js';
|
|
14
|
+
import '../../controller/controller_resolver.js';
|
|
15
|
+
import '../../testing-api.js';
|
|
16
|
+
import '@noego/ioc';
|
|
17
|
+
import '@noego/testing';
|
|
18
|
+
import '../../frontend/frontend_surface.js';
|
|
19
|
+
import '../../navigation/index.js';
|
|
20
|
+
import '../../navigation/layout_preservation.js';
|
|
21
|
+
import '../../navigation/automation_introspection.js';
|
|
22
|
+
import '../../loader/loader_orchestration.js';
|
|
23
|
+
import '../../frontend/page_catalog.js';
|
|
24
|
+
import '../../frontend/work_registry.js';
|
|
25
|
+
import '../../frontend/frontend_lifecycle.js';
|
|
26
|
+
import '../../frontend/frontend_page.js';
|
|
27
|
+
import '../wood_test_selection.js';
|
|
28
|
+
import '../wood_env_renderer.js';
|
|
29
|
+
import '../wood_dom_animation.js';
|
|
30
|
+
import '../registration_only_root.js';
|
|
31
|
+
import '../test_wood.js';
|
|
32
|
+
|
|
33
|
+
declare function openPlaywrightTab(inputs: NativeBrowserInputs, context: BrowserContext, bundle: NativeRendererBundle, route: NativeRendererRoute): Promise<NativeBrowserTab>;
|
|
34
|
+
|
|
35
|
+
export { openPlaywrightTab };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { assetContentType } from "@noego/testing/browser";
|
|
2
|
+
import { nativeHostTransport } from "./host_transport.js";
|
|
3
|
+
import { disposeNativeResources, hostDeadline } from "./native_browser_lifecycle.js";
|
|
4
|
+
function requestedAsset(bundle, pathname) {
|
|
5
|
+
const normalized = pathname.replace(/^\/+/, "");
|
|
6
|
+
for (const [fileName, asset] of bundle.assets) {
|
|
7
|
+
if (normalized === fileName || normalized.endsWith("/" + fileName)) return asset;
|
|
8
|
+
}
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
async function openPlaywrightTab(inputs, context, bundle, route) {
|
|
12
|
+
const page = await context.newPage();
|
|
13
|
+
const errors = [];
|
|
14
|
+
page.on("pageerror", (error) => errors.push(error.message));
|
|
15
|
+
const transport = nativeHostTransport(inputs, (channel, payload) => page.evaluate(({ channel: channel2, payload: payload2 }) => {
|
|
16
|
+
window.__woodNativeEmit(channel2, payload2);
|
|
17
|
+
}, { channel, payload }));
|
|
18
|
+
page.on("framenavigated", (frame) => {
|
|
19
|
+
if (frame === page.mainFrame()) transport.resetSubscriptions();
|
|
20
|
+
});
|
|
21
|
+
page.on("close", () => transport.dispose());
|
|
22
|
+
let closing = null;
|
|
23
|
+
const dispose = () => closing ?? (closing = disposeNativeResources("Wood Playwright tab cleanup failed", [
|
|
24
|
+
() => page.isClosed() ? void 0 : hostDeadline(page.evaluate(() => window.__woodNativeDispose?.()), "renderer teardown"),
|
|
25
|
+
() => transport.dispose(),
|
|
26
|
+
() => page.isClosed() ? void 0 : hostDeadline(transport.flush(), "event drain"),
|
|
27
|
+
() => page.close()
|
|
28
|
+
]));
|
|
29
|
+
try {
|
|
30
|
+
await page.exposeFunction("__woodNativeInvoke", transport.invoke);
|
|
31
|
+
await page.exposeFunction("__woodNativeSubscribe", transport.subscribe);
|
|
32
|
+
await page.exposeFunction("__woodNativeTrace", transport.trace);
|
|
33
|
+
await page.exposeFunction("__woodNativeLog", transport.log);
|
|
34
|
+
await page.addInitScript((input) => {
|
|
35
|
+
window.__woodNativeRoute = input;
|
|
36
|
+
globalThis.global = globalThis;
|
|
37
|
+
}, route);
|
|
38
|
+
const windowConfig = inputs.source.config.windows[route.page.split(".")[0]];
|
|
39
|
+
if (windowConfig) await page.setViewportSize({ width: windowConfig.width, height: windowConfig.height });
|
|
40
|
+
const url = `https://wood.test/${encodeURIComponent(route.page)}`;
|
|
41
|
+
const scriptUrl = `${url}/__wood.js`;
|
|
42
|
+
const cssUrl = `${url}/__wood.css`;
|
|
43
|
+
await page.route("https://wood.test/**", async (intercepted) => {
|
|
44
|
+
const requestUrl = intercepted.request().url();
|
|
45
|
+
if (requestUrl === url) {
|
|
46
|
+
await intercepted.fulfill({
|
|
47
|
+
contentType: "text/html",
|
|
48
|
+
body: `<!doctype html><html><head><meta charset="utf-8"><link rel="stylesheet" href="${cssUrl}"></head><body><div id="app"></div><script src="${scriptUrl}"></script></body></html>`
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (requestUrl === scriptUrl) {
|
|
53
|
+
await intercepted.fulfill({ contentType: "text/javascript", body: bundle.code });
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (requestUrl === cssUrl) {
|
|
57
|
+
await intercepted.fulfill({ contentType: "text/css", body: bundle.css });
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const asset = requestedAsset(bundle, new URL(requestUrl).pathname);
|
|
61
|
+
if (asset) {
|
|
62
|
+
await intercepted.fulfill({ contentType: assetContentType(asset.fileName), body: Buffer.from(asset.source) });
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
await intercepted.fulfill({ status: 404, contentType: "text/plain", body: "Wood native asset not found" });
|
|
66
|
+
});
|
|
67
|
+
await page.goto(url);
|
|
68
|
+
await hostDeadline(page.evaluate(() => window.__woodNativeReady), "initial mount");
|
|
69
|
+
if (errors.length) throw new Error(errors.join("\n"));
|
|
70
|
+
return {
|
|
71
|
+
native: page,
|
|
72
|
+
async flush() {
|
|
73
|
+
if (page.isClosed()) return;
|
|
74
|
+
await hostDeadline(page.evaluate(() => window.__woodNativeFlush()), "renderer flush");
|
|
75
|
+
await hostDeadline(transport.flush(), "event flush");
|
|
76
|
+
await page.evaluate(() => window.__woodNativeFlush());
|
|
77
|
+
},
|
|
78
|
+
dispose
|
|
79
|
+
};
|
|
80
|
+
} catch (error) {
|
|
81
|
+
let html = "";
|
|
82
|
+
if (!page.isClosed()) {
|
|
83
|
+
try {
|
|
84
|
+
html = (await page.content()).slice(0, 4e3);
|
|
85
|
+
} catch {
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const primary = Object.assign(new Error(`Wood could not open ${route.page}: ${error instanceof Error ? error.message : String(error)}
|
|
89
|
+
${errors.join("\n")}
|
|
90
|
+
${html}`), { cause: error });
|
|
91
|
+
await disposeNativeResources("Wood browser open failed", [() => {
|
|
92
|
+
throw primary;
|
|
93
|
+
}, dispose]);
|
|
94
|
+
throw primary;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export {
|
|
98
|
+
openPlaywrightTab
|
|
99
|
+
};
|
|
100
|
+
//# sourceMappingURL=playwright_tab.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/testing/native_browser/playwright_tab.ts"],"sourcesContent":["import { assetContentType } from '@noego/testing/browser';\nimport type { BrowserContext } from 'playwright';\nimport type { NativeBrowserInputs, NativeBrowserTab, NativeRendererBundle, NativeRendererRoute } from './native_browser.types.js';\nimport { nativeHostTransport } from './host_transport.js';\nimport { disposeNativeResources, hostDeadline } from './native_browser_lifecycle.js';\n\n\nfunction requestedAsset(bundle: NativeRendererBundle, pathname: string) {\n const normalized = pathname.replace(/^\\/+/, '');\n for (const [fileName, asset] of bundle.assets) {\n if (normalized === fileName || normalized.endsWith('/' + fileName)) return asset;\n }\n return null;\n}\n\nexport async function openPlaywrightTab(\n inputs: NativeBrowserInputs, context: BrowserContext, bundle: NativeRendererBundle, route: NativeRendererRoute,\n): Promise<NativeBrowserTab> {\n const page = await context.newPage();\n const errors: string[] = [];\n page.on('pageerror', error => errors.push(error.message));\n const transport = nativeHostTransport(inputs, (channel, payload) => page.evaluate(({channel, payload}) => {\n (window as any).__woodNativeEmit(channel, payload);\n }, {channel, payload}));\n page.on('framenavigated', frame => {\n if (frame === page.mainFrame()) transport.resetSubscriptions();\n });\n page.on('close', () => transport.dispose());\n let closing: Promise<void> | null = null;\n const dispose = () => closing ??= disposeNativeResources('Wood Playwright tab cleanup failed', [\n () => page.isClosed() ? undefined : hostDeadline(page.evaluate(() => (window as any).__woodNativeDispose?.()), 'renderer teardown'),\n () => transport.dispose(),\n () => page.isClosed() ? undefined : hostDeadline(transport.flush(), 'event drain'),\n () => page.close(),\n ]);\n try {\n await page.exposeFunction('__woodNativeInvoke', transport.invoke);\n await page.exposeFunction('__woodNativeSubscribe', transport.subscribe);\n await page.exposeFunction('__woodNativeTrace', transport.trace);\n await page.exposeFunction('__woodNativeLog', transport.log);\n await page.addInitScript(input => {\n (window as any).__woodNativeRoute = input;\n (globalThis as any).global = globalThis;\n }, route);\n const windowConfig = inputs.source.config.windows[route.page.split('.')[0]!];\n if (windowConfig) await page.setViewportSize({width: windowConfig.width, height: windowConfig.height});\n // A real origin permits native cookies/localStorage. Bundle assets are\n // inlined by Vite library mode; no per-test Vite server or browser launch.\n const url = `https://wood.test/${encodeURIComponent(route.page)}`;\n const scriptUrl = `${url}/__wood.js`;\n const cssUrl = `${url}/__wood.css`;\n await page.route('https://wood.test/**', async intercepted => {\n const requestUrl = intercepted.request().url();\n if (requestUrl === url) {\n await intercepted.fulfill({\n contentType: 'text/html',\n body: `<!doctype html><html><head><meta charset=\"utf-8\"><link rel=\"stylesheet\" href=\"${cssUrl}\"></head><body><div id=\"app\"></div><script src=\"${scriptUrl}\"></script></body></html>`,\n });\n return;\n }\n if (requestUrl === scriptUrl) {\n await intercepted.fulfill({contentType: 'text/javascript', body: bundle.code});\n return;\n }\n if (requestUrl === cssUrl) {\n await intercepted.fulfill({contentType: 'text/css', body: bundle.css});\n return;\n }\n const asset = requestedAsset(bundle, new URL(requestUrl).pathname);\n if (asset) {\n await intercepted.fulfill({contentType: assetContentType(asset.fileName), body: Buffer.from(asset.source)});\n return;\n }\n await intercepted.fulfill({status: 404, contentType: 'text/plain', body: 'Wood native asset not found'});\n });\n await page.goto(url);\n await hostDeadline(page.evaluate(() => (window as any).__woodNativeReady), 'initial mount');\n if (errors.length) throw new Error(errors.join('\\n'));\n return {\n native: page,\n async flush() {\n if (page.isClosed()) return;\n await hostDeadline(page.evaluate(() => (window as any).__woodNativeFlush()), 'renderer flush');\n await hostDeadline(transport.flush(), 'event flush');\n await page.evaluate(() => (window as any).__woodNativeFlush());\n },\n dispose,\n };\n } catch (error) {\n let html = '';\n if (!page.isClosed()) { try {html = (await page.content()).slice(0, 4000);} catch {} }\n const primary = Object.assign(new Error(`Wood could not open ${route.page}: ${error instanceof Error ? error.message : String(error)}\\n${errors.join('\\n')}\\n${html}`), {cause: error});\n await disposeNativeResources('Wood browser open failed', [() => {throw primary;}, dispose]);\n throw primary;\n }\n}\n"],"mappings":"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","names":["channel","payload"]}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var renderer_compilation_exports = {};
|
|
30
|
+
__export(renderer_compilation_exports, {
|
|
31
|
+
compileNativeRenderer: () => compileNativeRenderer
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(renderer_compilation_exports);
|
|
34
|
+
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
35
|
+
var import_node_os = __toESM(require("node:os"), 1);
|
|
36
|
+
var import_node_path = __toESM(require("node:path"), 1);
|
|
37
|
+
var import_loader_orchestration = require("../../loader/loader_orchestration.js");
|
|
38
|
+
var import_renderer_app_generator = require("../../codegen/renderer_app_generator.js");
|
|
39
|
+
var import_browser = require("@noego/testing/browser");
|
|
40
|
+
var import_renderer_entry = require("./renderer_entry.js");
|
|
41
|
+
const compilations = /* @__PURE__ */ new Map();
|
|
42
|
+
const MAX_COMPILATIONS = 32;
|
|
43
|
+
function stamp(file) {
|
|
44
|
+
try {
|
|
45
|
+
const s = import_node_fs.default.statSync(file);
|
|
46
|
+
return `${s.mtimeMs}:${s.size}`;
|
|
47
|
+
} catch {
|
|
48
|
+
return "missing";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function compileNativeRenderer(inputs) {
|
|
52
|
+
const { source, views } = inputs;
|
|
53
|
+
const key = JSON.stringify([source.configPath, views, [...source.operations], source.config.renderer.css ?? []]);
|
|
54
|
+
let pending = compilations.get(key);
|
|
55
|
+
if (pending) {
|
|
56
|
+
const existing = await pending;
|
|
57
|
+
if ([...existing.files].every(([file, previous]) => stamp(file) === previous)) {
|
|
58
|
+
compilations.delete(key);
|
|
59
|
+
compilations.set(key, pending);
|
|
60
|
+
return existing.bundle;
|
|
61
|
+
}
|
|
62
|
+
compilations.delete(key);
|
|
63
|
+
}
|
|
64
|
+
pending = compile(inputs);
|
|
65
|
+
compilations.set(key, pending);
|
|
66
|
+
while (compilations.size > MAX_COMPILATIONS) compilations.delete(compilations.keys().next().value);
|
|
67
|
+
try {
|
|
68
|
+
return (await pending).bundle;
|
|
69
|
+
} catch (error) {
|
|
70
|
+
if (compilations.get(key) === pending) compilations.delete(key);
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function compile({ source, views }) {
|
|
75
|
+
const temporary = import_node_fs.default.realpathSync(import_node_fs.default.mkdtempSync(import_node_path.default.join(import_node_os.default.tmpdir(), "wood-native-renderer-")));
|
|
76
|
+
try {
|
|
77
|
+
const { build, svelte } = await (0, import_browser.loadBrowserCompiler)(source.configDir);
|
|
78
|
+
if (!svelte) throw new Error(".browser() requires @sveltejs/vite-plugin-svelte in the application");
|
|
79
|
+
const entry = import_node_path.default.join(temporary, "entry.ts");
|
|
80
|
+
import_node_fs.default.writeFileSync(import_node_path.default.join(temporary, "app.ts"), (0, import_renderer_app_generator.generateRendererApp)([...views], {
|
|
81
|
+
componentDir: source.rendererComponentDir,
|
|
82
|
+
outDir: temporary
|
|
83
|
+
}));
|
|
84
|
+
const cssImports = (source.config.renderer.css ?? []).map((file) => `import ${JSON.stringify(import_node_path.default.resolve(source.configDir, file))};`).join("\n");
|
|
85
|
+
import_node_fs.default.writeFileSync(entry, `${cssImports}
|
|
86
|
+
${(0, import_renderer_entry.nativeRendererEntry)(source)}`);
|
|
87
|
+
let dependencies = [];
|
|
88
|
+
const output = await build({
|
|
89
|
+
configFile: false,
|
|
90
|
+
root: source.configDir,
|
|
91
|
+
mode: "test",
|
|
92
|
+
logLevel: process.env.WOOD_BROWSER_TEST_DEBUG ? "info" : "silent",
|
|
93
|
+
plugins: [(0, import_browser.createBrowserResolver)(source.configDir), svelte({ hot: false }), {
|
|
94
|
+
name: "wood-native-compilation-dependencies",
|
|
95
|
+
generateBundle() {
|
|
96
|
+
dependencies = this.getModuleIds ? [...this.getModuleIds()] : [];
|
|
97
|
+
}
|
|
98
|
+
}],
|
|
99
|
+
resolve: { dedupe: ["svelte", "@noego/ioc"], conditions: ["browser"] },
|
|
100
|
+
define: { "global": "globalThis", "process.env.NODE_ENV": JSON.stringify("test") },
|
|
101
|
+
build: {
|
|
102
|
+
write: false,
|
|
103
|
+
emptyOutDir: false,
|
|
104
|
+
minify: false,
|
|
105
|
+
target: "esnext",
|
|
106
|
+
cssCodeSplit: false,
|
|
107
|
+
lib: { entry, name: "WoodNativeRenderer", formats: ["iife"] },
|
|
108
|
+
rollupOptions: { output: { inlineDynamicImports: true } }
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
if ("on" in output) throw new Error("Native renderer compilation unexpectedly started a watcher");
|
|
112
|
+
const outputs = Array.isArray(output) ? output : [output];
|
|
113
|
+
let code = "";
|
|
114
|
+
let css = "";
|
|
115
|
+
const assets = /* @__PURE__ */ new Map();
|
|
116
|
+
for (const result of outputs) for (const item of result.output) {
|
|
117
|
+
if (item.type === "chunk") {
|
|
118
|
+
if (item.isEntry) code += item.code;
|
|
119
|
+
else assets.set(item.fileName, { fileName: item.fileName, source: new TextEncoder().encode(item.code) });
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (item.fileName.endsWith(".css")) {
|
|
123
|
+
css += typeof item.source === "string" ? item.source : new TextDecoder().decode(item.source);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const source2 = typeof item.source === "string" ? new TextEncoder().encode(item.source) : new Uint8Array(item.source);
|
|
127
|
+
assets.set(item.fileName, { fileName: item.fileName, source: source2 });
|
|
128
|
+
}
|
|
129
|
+
if (!code) throw new Error("Native renderer compiler returned no JavaScript");
|
|
130
|
+
const files = new Map(dependencies.map((file) => file.split("?")[0]).filter((file) => import_node_path.default.isAbsolute(file) && !file.startsWith(temporary)).map((file) => [file, stamp(file)]));
|
|
131
|
+
for (const view of views) for (const component of [...view.layouts, view.viewPath]) {
|
|
132
|
+
for (const loader of (0, import_loader_orchestration.loaderCompanionCandidates)(component)) {
|
|
133
|
+
const file = import_node_path.default.resolve(source.rendererComponentDir, loader);
|
|
134
|
+
files.set(file, stamp(file));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
for (const file of [source.configPath, import_node_path.default.join(source.configDir, "package.json"), import_node_path.default.join(source.configDir, "package-lock.json")]) {
|
|
138
|
+
files.set(file, stamp(file));
|
|
139
|
+
}
|
|
140
|
+
return { bundle: { code, css, assets }, files };
|
|
141
|
+
} finally {
|
|
142
|
+
import_node_fs.default.rmSync(temporary, { recursive: true, force: true });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
146
|
+
0 && (module.exports = {
|
|
147
|
+
compileNativeRenderer
|
|
148
|
+
});
|
|
149
|
+
//# sourceMappingURL=renderer_compilation.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/testing/native_browser/renderer_compilation.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { loaderCompanionCandidates } from '../../loader/loader_orchestration.js';\nimport { generateRendererApp } from '../../codegen/renderer_app_generator.js';\nimport { createBrowserResolver, loadBrowserCompiler } from '@noego/testing/browser';\nimport { nativeRendererEntry } from './renderer_entry.js';\nimport type { NativeBrowserInputs, NativeRendererBundle } from './native_browser.types.js';\n\ninterface Compilation {\n bundle: NativeRendererBundle;\n files: ReadonlyMap<string, string>;\n}\n// Code and file stamps only. Renderer instances, globals, roots and rows are\n// NEVER cached; every tab/window evaluates the bundle in its own realm.\nconst compilations = new Map<string, Promise<Compilation>>();\nconst MAX_COMPILATIONS = 32;\nfunction stamp(file: string): string {\n try { const s = fs.statSync(file); return `${s.mtimeMs}:${s.size}`; }\n catch { return 'missing'; }\n}\n\nexport async function compileNativeRenderer(inputs: NativeBrowserInputs): Promise<NativeRendererBundle> {\n const { source, views } = inputs;\n const key = JSON.stringify([source.configPath, views, [...source.operations], source.config.renderer.css ?? []]);\n let pending = compilations.get(key);\n if (pending) {\n const existing = await pending;\n if ([...existing.files].every(([file, previous]) => stamp(file) === previous)) {\n // LRU without retaining application environments, windows or closures.\n compilations.delete(key);\n compilations.set(key, pending);\n return existing.bundle;\n }\n compilations.delete(key);\n }\n pending = compile(inputs);\n compilations.set(key, pending);\n while (compilations.size > MAX_COMPILATIONS) compilations.delete(compilations.keys().next().value!);\n try { return (await pending).bundle; }\n catch (error) { if (compilations.get(key) === pending) compilations.delete(key); throw error; }\n}\n\nasync function compile({ source, views }: NativeBrowserInputs): Promise<Compilation> {\n const temporary = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'wood-native-renderer-')));\n try {\n const {build, svelte} = await loadBrowserCompiler(source.configDir);\n if (!svelte) throw new Error('.browser() requires @sveltejs/vite-plugin-svelte in the application');\n const entry = path.join(temporary, 'entry.ts');\n fs.writeFileSync(path.join(temporary, 'app.ts'), generateRendererApp([...views], {\n componentDir: source.rendererComponentDir, outDir: temporary,\n }));\n const cssImports = (source.config.renderer.css ?? []).map(file =>\n `import ${JSON.stringify(path.resolve(source.configDir, file))};`).join('\\n');\n fs.writeFileSync(entry, `${cssImports}\\n${nativeRendererEntry(source)}`);\n let dependencies: string[] = [];\n const output = await build({\n configFile: false,\n root: source.configDir,\n mode: 'test',\n logLevel: process.env.WOOD_BROWSER_TEST_DEBUG ? 'info' : 'silent',\n plugins: [createBrowserResolver(source.configDir), svelte({hot: false}), {\n name: 'wood-native-compilation-dependencies',\n generateBundle() { dependencies = this.getModuleIds ? [...this.getModuleIds()] : []; },\n }],\n resolve: { dedupe: ['svelte', '@noego/ioc'], conditions: ['browser'] },\n define: {'global': 'globalThis', 'process.env.NODE_ENV': JSON.stringify('test')},\n build: {\n write: false, emptyOutDir: false, minify: false, target: 'esnext',\n cssCodeSplit: false,\n lib: {entry, name: 'WoodNativeRenderer', formats: ['iife']},\n rollupOptions: {output: {inlineDynamicImports: true}},\n },\n });\n if ('on' in output) throw new Error('Native renderer compilation unexpectedly started a watcher');\n const outputs = Array.isArray(output) ? output : [output];\n let code = ''; let css = '';\n const assets = new Map<string, {fileName: string; source: Uint8Array}>();\n for (const result of outputs) for (const item of result.output) {\n if (item.type === 'chunk') {\n if (item.isEntry) code += item.code;\n else assets.set(item.fileName, {fileName: item.fileName, source: new TextEncoder().encode(item.code)});\n continue;\n }\n if (item.fileName.endsWith('.css')) {\n css += typeof item.source === 'string' ? item.source : new TextDecoder().decode(item.source);\n continue;\n }\n const source = typeof item.source === 'string' ? new TextEncoder().encode(item.source) : new Uint8Array(item.source);\n assets.set(item.fileName, {fileName: item.fileName, source});\n }\n if (!code) throw new Error('Native renderer compiler returned no JavaScript');\n // Rollup IDs may include ?raw / ?url; the disk dependency is the part\n // before the query. Do not cache a permanent \"missing\" stamp for YAML.\n const files = new Map(dependencies.map(file => file.split('?')[0]!)\n .filter(file => path.isAbsolute(file) && !file.startsWith(temporary))\n .map(file => [file, stamp(file)]));\n // Adding a formerly absent companion must invalidate codegen as well.\n for (const view of views) for (const component of [...view.layouts, view.viewPath]) {\n for (const loader of loaderCompanionCandidates(component)) {\n const file = path.resolve(source.rendererComponentDir, loader);\n files.set(file, stamp(file));\n }\n }\n for (const file of [source.configPath, path.join(source.configDir, 'package.json'), path.join(source.configDir, 'package-lock.json')]) {\n files.set(file, stamp(file));\n }\n return {bundle: {code, css, assets}, files};\n } finally { fs.rmSync(temporary, {recursive: true, force: true}); }\n}\n"],"mappings":"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","names":["fs","path","os","source"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { h as NativeBrowserInputs, i as NativeRendererBundle } from '../../native_browser.types-vWXtE4rM.cjs';
|
|
2
|
+
import '@noego/testing/fetch';
|
|
3
|
+
import 'playwright';
|
|
4
|
+
import 'happy-dom';
|
|
5
|
+
import '../wood_config_source.cjs';
|
|
6
|
+
import '../../types/config.cjs';
|
|
7
|
+
import '../../types/operations.cjs';
|
|
8
|
+
import '../../types/views.cjs';
|
|
9
|
+
import '../create_router_bridge.cjs';
|
|
10
|
+
import '../../router/wood_router.cjs';
|
|
11
|
+
import '../../types/context.cjs';
|
|
12
|
+
import '../../validation/schema_validator.cjs';
|
|
13
|
+
import '../../middleware/middleware_resolver.cjs';
|
|
14
|
+
import '../../controller/controller_resolver.cjs';
|
|
15
|
+
import '../../testing-api.cjs';
|
|
16
|
+
import '@noego/ioc';
|
|
17
|
+
import '@noego/testing';
|
|
18
|
+
import '../../frontend/frontend_surface.cjs';
|
|
19
|
+
import '../../navigation/index.cjs';
|
|
20
|
+
import '../../navigation/layout_preservation.cjs';
|
|
21
|
+
import '../../navigation/automation_introspection.cjs';
|
|
22
|
+
import '../../loader/loader_orchestration.cjs';
|
|
23
|
+
import '../../frontend/page_catalog.cjs';
|
|
24
|
+
import '../../frontend/work_registry.cjs';
|
|
25
|
+
import '../../frontend/frontend_lifecycle.cjs';
|
|
26
|
+
import '../../frontend/frontend_page.cjs';
|
|
27
|
+
import '../wood_test_selection.cjs';
|
|
28
|
+
import '../wood_env_renderer.cjs';
|
|
29
|
+
import '../wood_dom_animation.cjs';
|
|
30
|
+
import '../registration_only_root.cjs';
|
|
31
|
+
import '../test_wood.cjs';
|
|
32
|
+
|
|
33
|
+
declare function compileNativeRenderer(inputs: NativeBrowserInputs): Promise<NativeRendererBundle>;
|
|
34
|
+
|
|
35
|
+
export { compileNativeRenderer };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { h as NativeBrowserInputs, i as NativeRendererBundle } from '../../native_browser.types-BY2daUOS.js';
|
|
2
|
+
import '@noego/testing/fetch';
|
|
3
|
+
import 'playwright';
|
|
4
|
+
import 'happy-dom';
|
|
5
|
+
import '../wood_config_source.js';
|
|
6
|
+
import '../../types/config.js';
|
|
7
|
+
import '../../types/operations.js';
|
|
8
|
+
import '../../types/views.js';
|
|
9
|
+
import '../create_router_bridge.js';
|
|
10
|
+
import '../../router/wood_router.js';
|
|
11
|
+
import '../../types/context.js';
|
|
12
|
+
import '../../validation/schema_validator.js';
|
|
13
|
+
import '../../middleware/middleware_resolver.js';
|
|
14
|
+
import '../../controller/controller_resolver.js';
|
|
15
|
+
import '../../testing-api.js';
|
|
16
|
+
import '@noego/ioc';
|
|
17
|
+
import '@noego/testing';
|
|
18
|
+
import '../../frontend/frontend_surface.js';
|
|
19
|
+
import '../../navigation/index.js';
|
|
20
|
+
import '../../navigation/layout_preservation.js';
|
|
21
|
+
import '../../navigation/automation_introspection.js';
|
|
22
|
+
import '../../loader/loader_orchestration.js';
|
|
23
|
+
import '../../frontend/page_catalog.js';
|
|
24
|
+
import '../../frontend/work_registry.js';
|
|
25
|
+
import '../../frontend/frontend_lifecycle.js';
|
|
26
|
+
import '../../frontend/frontend_page.js';
|
|
27
|
+
import '../wood_test_selection.js';
|
|
28
|
+
import '../wood_env_renderer.js';
|
|
29
|
+
import '../wood_dom_animation.js';
|
|
30
|
+
import '../registration_only_root.js';
|
|
31
|
+
import '../test_wood.js';
|
|
32
|
+
|
|
33
|
+
declare function compileNativeRenderer(inputs: NativeBrowserInputs): Promise<NativeRendererBundle>;
|
|
34
|
+
|
|
35
|
+
export { compileNativeRenderer };
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { loaderCompanionCandidates } from "../../loader/loader_orchestration.js";
|
|
5
|
+
import { generateRendererApp } from "../../codegen/renderer_app_generator.js";
|
|
6
|
+
import { createBrowserResolver, loadBrowserCompiler } from "@noego/testing/browser";
|
|
7
|
+
import { nativeRendererEntry } from "./renderer_entry.js";
|
|
8
|
+
const compilations = /* @__PURE__ */ new Map();
|
|
9
|
+
const MAX_COMPILATIONS = 32;
|
|
10
|
+
function stamp(file) {
|
|
11
|
+
try {
|
|
12
|
+
const s = fs.statSync(file);
|
|
13
|
+
return `${s.mtimeMs}:${s.size}`;
|
|
14
|
+
} catch {
|
|
15
|
+
return "missing";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function compileNativeRenderer(inputs) {
|
|
19
|
+
const { source, views } = inputs;
|
|
20
|
+
const key = JSON.stringify([source.configPath, views, [...source.operations], source.config.renderer.css ?? []]);
|
|
21
|
+
let pending = compilations.get(key);
|
|
22
|
+
if (pending) {
|
|
23
|
+
const existing = await pending;
|
|
24
|
+
if ([...existing.files].every(([file, previous]) => stamp(file) === previous)) {
|
|
25
|
+
compilations.delete(key);
|
|
26
|
+
compilations.set(key, pending);
|
|
27
|
+
return existing.bundle;
|
|
28
|
+
}
|
|
29
|
+
compilations.delete(key);
|
|
30
|
+
}
|
|
31
|
+
pending = compile(inputs);
|
|
32
|
+
compilations.set(key, pending);
|
|
33
|
+
while (compilations.size > MAX_COMPILATIONS) compilations.delete(compilations.keys().next().value);
|
|
34
|
+
try {
|
|
35
|
+
return (await pending).bundle;
|
|
36
|
+
} catch (error) {
|
|
37
|
+
if (compilations.get(key) === pending) compilations.delete(key);
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async function compile({ source, views }) {
|
|
42
|
+
const temporary = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), "wood-native-renderer-")));
|
|
43
|
+
try {
|
|
44
|
+
const { build, svelte } = await loadBrowserCompiler(source.configDir);
|
|
45
|
+
if (!svelte) throw new Error(".browser() requires @sveltejs/vite-plugin-svelte in the application");
|
|
46
|
+
const entry = path.join(temporary, "entry.ts");
|
|
47
|
+
fs.writeFileSync(path.join(temporary, "app.ts"), generateRendererApp([...views], {
|
|
48
|
+
componentDir: source.rendererComponentDir,
|
|
49
|
+
outDir: temporary
|
|
50
|
+
}));
|
|
51
|
+
const cssImports = (source.config.renderer.css ?? []).map((file) => `import ${JSON.stringify(path.resolve(source.configDir, file))};`).join("\n");
|
|
52
|
+
fs.writeFileSync(entry, `${cssImports}
|
|
53
|
+
${nativeRendererEntry(source)}`);
|
|
54
|
+
let dependencies = [];
|
|
55
|
+
const output = await build({
|
|
56
|
+
configFile: false,
|
|
57
|
+
root: source.configDir,
|
|
58
|
+
mode: "test",
|
|
59
|
+
logLevel: process.env.WOOD_BROWSER_TEST_DEBUG ? "info" : "silent",
|
|
60
|
+
plugins: [createBrowserResolver(source.configDir), svelte({ hot: false }), {
|
|
61
|
+
name: "wood-native-compilation-dependencies",
|
|
62
|
+
generateBundle() {
|
|
63
|
+
dependencies = this.getModuleIds ? [...this.getModuleIds()] : [];
|
|
64
|
+
}
|
|
65
|
+
}],
|
|
66
|
+
resolve: { dedupe: ["svelte", "@noego/ioc"], conditions: ["browser"] },
|
|
67
|
+
define: { "global": "globalThis", "process.env.NODE_ENV": JSON.stringify("test") },
|
|
68
|
+
build: {
|
|
69
|
+
write: false,
|
|
70
|
+
emptyOutDir: false,
|
|
71
|
+
minify: false,
|
|
72
|
+
target: "esnext",
|
|
73
|
+
cssCodeSplit: false,
|
|
74
|
+
lib: { entry, name: "WoodNativeRenderer", formats: ["iife"] },
|
|
75
|
+
rollupOptions: { output: { inlineDynamicImports: true } }
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
if ("on" in output) throw new Error("Native renderer compilation unexpectedly started a watcher");
|
|
79
|
+
const outputs = Array.isArray(output) ? output : [output];
|
|
80
|
+
let code = "";
|
|
81
|
+
let css = "";
|
|
82
|
+
const assets = /* @__PURE__ */ new Map();
|
|
83
|
+
for (const result of outputs) for (const item of result.output) {
|
|
84
|
+
if (item.type === "chunk") {
|
|
85
|
+
if (item.isEntry) code += item.code;
|
|
86
|
+
else assets.set(item.fileName, { fileName: item.fileName, source: new TextEncoder().encode(item.code) });
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (item.fileName.endsWith(".css")) {
|
|
90
|
+
css += typeof item.source === "string" ? item.source : new TextDecoder().decode(item.source);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const source2 = typeof item.source === "string" ? new TextEncoder().encode(item.source) : new Uint8Array(item.source);
|
|
94
|
+
assets.set(item.fileName, { fileName: item.fileName, source: source2 });
|
|
95
|
+
}
|
|
96
|
+
if (!code) throw new Error("Native renderer compiler returned no JavaScript");
|
|
97
|
+
const files = new Map(dependencies.map((file) => file.split("?")[0]).filter((file) => path.isAbsolute(file) && !file.startsWith(temporary)).map((file) => [file, stamp(file)]));
|
|
98
|
+
for (const view of views) for (const component of [...view.layouts, view.viewPath]) {
|
|
99
|
+
for (const loader of loaderCompanionCandidates(component)) {
|
|
100
|
+
const file = path.resolve(source.rendererComponentDir, loader);
|
|
101
|
+
files.set(file, stamp(file));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
for (const file of [source.configPath, path.join(source.configDir, "package.json"), path.join(source.configDir, "package-lock.json")]) {
|
|
105
|
+
files.set(file, stamp(file));
|
|
106
|
+
}
|
|
107
|
+
return { bundle: { code, css, assets }, files };
|
|
108
|
+
} finally {
|
|
109
|
+
fs.rmSync(temporary, { recursive: true, force: true });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
export {
|
|
113
|
+
compileNativeRenderer
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=renderer_compilation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/testing/native_browser/renderer_compilation.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { loaderCompanionCandidates } from '../../loader/loader_orchestration.js';\nimport { generateRendererApp } from '../../codegen/renderer_app_generator.js';\nimport { createBrowserResolver, loadBrowserCompiler } from '@noego/testing/browser';\nimport { nativeRendererEntry } from './renderer_entry.js';\nimport type { NativeBrowserInputs, NativeRendererBundle } from './native_browser.types.js';\n\ninterface Compilation {\n bundle: NativeRendererBundle;\n files: ReadonlyMap<string, string>;\n}\n// Code and file stamps only. Renderer instances, globals, roots and rows are\n// NEVER cached; every tab/window evaluates the bundle in its own realm.\nconst compilations = new Map<string, Promise<Compilation>>();\nconst MAX_COMPILATIONS = 32;\nfunction stamp(file: string): string {\n try { const s = fs.statSync(file); return `${s.mtimeMs}:${s.size}`; }\n catch { return 'missing'; }\n}\n\nexport async function compileNativeRenderer(inputs: NativeBrowserInputs): Promise<NativeRendererBundle> {\n const { source, views } = inputs;\n const key = JSON.stringify([source.configPath, views, [...source.operations], source.config.renderer.css ?? []]);\n let pending = compilations.get(key);\n if (pending) {\n const existing = await pending;\n if ([...existing.files].every(([file, previous]) => stamp(file) === previous)) {\n // LRU without retaining application environments, windows or closures.\n compilations.delete(key);\n compilations.set(key, pending);\n return existing.bundle;\n }\n compilations.delete(key);\n }\n pending = compile(inputs);\n compilations.set(key, pending);\n while (compilations.size > MAX_COMPILATIONS) compilations.delete(compilations.keys().next().value!);\n try { return (await pending).bundle; }\n catch (error) { if (compilations.get(key) === pending) compilations.delete(key); throw error; }\n}\n\nasync function compile({ source, views }: NativeBrowserInputs): Promise<Compilation> {\n const temporary = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'wood-native-renderer-')));\n try {\n const {build, svelte} = await loadBrowserCompiler(source.configDir);\n if (!svelte) throw new Error('.browser() requires @sveltejs/vite-plugin-svelte in the application');\n const entry = path.join(temporary, 'entry.ts');\n fs.writeFileSync(path.join(temporary, 'app.ts'), generateRendererApp([...views], {\n componentDir: source.rendererComponentDir, outDir: temporary,\n }));\n const cssImports = (source.config.renderer.css ?? []).map(file =>\n `import ${JSON.stringify(path.resolve(source.configDir, file))};`).join('\\n');\n fs.writeFileSync(entry, `${cssImports}\\n${nativeRendererEntry(source)}`);\n let dependencies: string[] = [];\n const output = await build({\n configFile: false,\n root: source.configDir,\n mode: 'test',\n logLevel: process.env.WOOD_BROWSER_TEST_DEBUG ? 'info' : 'silent',\n plugins: [createBrowserResolver(source.configDir), svelte({hot: false}), {\n name: 'wood-native-compilation-dependencies',\n generateBundle() { dependencies = this.getModuleIds ? [...this.getModuleIds()] : []; },\n }],\n resolve: { dedupe: ['svelte', '@noego/ioc'], conditions: ['browser'] },\n define: {'global': 'globalThis', 'process.env.NODE_ENV': JSON.stringify('test')},\n build: {\n write: false, emptyOutDir: false, minify: false, target: 'esnext',\n cssCodeSplit: false,\n lib: {entry, name: 'WoodNativeRenderer', formats: ['iife']},\n rollupOptions: {output: {inlineDynamicImports: true}},\n },\n });\n if ('on' in output) throw new Error('Native renderer compilation unexpectedly started a watcher');\n const outputs = Array.isArray(output) ? output : [output];\n let code = ''; let css = '';\n const assets = new Map<string, {fileName: string; source: Uint8Array}>();\n for (const result of outputs) for (const item of result.output) {\n if (item.type === 'chunk') {\n if (item.isEntry) code += item.code;\n else assets.set(item.fileName, {fileName: item.fileName, source: new TextEncoder().encode(item.code)});\n continue;\n }\n if (item.fileName.endsWith('.css')) {\n css += typeof item.source === 'string' ? item.source : new TextDecoder().decode(item.source);\n continue;\n }\n const source = typeof item.source === 'string' ? new TextEncoder().encode(item.source) : new Uint8Array(item.source);\n assets.set(item.fileName, {fileName: item.fileName, source});\n }\n if (!code) throw new Error('Native renderer compiler returned no JavaScript');\n // Rollup IDs may include ?raw / ?url; the disk dependency is the part\n // before the query. Do not cache a permanent \"missing\" stamp for YAML.\n const files = new Map(dependencies.map(file => file.split('?')[0]!)\n .filter(file => path.isAbsolute(file) && !file.startsWith(temporary))\n .map(file => [file, stamp(file)]));\n // Adding a formerly absent companion must invalidate codegen as well.\n for (const view of views) for (const component of [...view.layouts, view.viewPath]) {\n for (const loader of loaderCompanionCandidates(component)) {\n const file = path.resolve(source.rendererComponentDir, loader);\n files.set(file, stamp(file));\n }\n }\n for (const file of [source.configPath, path.join(source.configDir, 'package.json'), path.join(source.configDir, 'package-lock.json')]) {\n files.set(file, stamp(file));\n }\n return {bundle: {code, css, assets}, files};\n } finally { fs.rmSync(temporary, {recursive: true, force: true}); }\n}\n"],"mappings":"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","names":["source"]}
|