@noego/wood 0.7.2 → 0.7.4
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/bin/wood.js +9 -1
- package/dist/codegen/renderer_app_generator.cjs +14 -13
- package/dist/codegen/renderer_app_generator.cjs.map +1 -1
- package/dist/codegen/renderer_app_generator.js +14 -13
- package/dist/codegen/renderer_app_generator.js.map +1 -1
- package/dist/navigation/index.cjs +14 -0
- package/dist/navigation/index.cjs.map +1 -1
- package/dist/navigation/index.d.cts +3 -1
- package/dist/navigation/index.d.ts +3 -1
- package/dist/navigation/index.js +13 -0
- package/dist/navigation/index.js.map +1 -1
- package/dist/testing/browser.cjs +11 -1
- package/dist/testing/browser.cjs.map +1 -1
- package/dist/testing/browser.d.cts +7 -1
- package/dist/testing/browser.d.ts +7 -1
- package/dist/testing/browser.js +10 -1
- package/dist/testing/browser.js.map +1 -1
- package/dist/testing/native_browser/happy_dom_tab.cjs +3 -2
- package/dist/testing/native_browser/happy_dom_tab.cjs.map +1 -1
- package/dist/testing/native_browser/happy_dom_tab.js +3 -2
- package/dist/testing/native_browser/happy_dom_tab.js.map +1 -1
- package/dist/testing/native_browser/host_transport.cjs +18 -8
- package/dist/testing/native_browser/host_transport.cjs.map +1 -1
- package/dist/testing/native_browser/host_transport.d.cts +3 -3
- package/dist/testing/native_browser/host_transport.d.ts +3 -3
- package/dist/testing/native_browser/host_transport.js +18 -8
- package/dist/testing/native_browser/host_transport.js.map +1 -1
- package/dist/testing/native_browser/playwright_tab.cjs +4 -6
- package/dist/testing/native_browser/playwright_tab.cjs.map +1 -1
- package/dist/testing/native_browser/playwright_tab.js +4 -6
- package/dist/testing/native_browser/playwright_tab.js.map +1 -1
- package/dist/testing/native_browser/renderer_entry.cjs +5 -2
- package/dist/testing/native_browser/renderer_entry.cjs.map +1 -1
- package/dist/testing/native_browser/renderer_entry.js +5 -2
- package/dist/testing/native_browser/renderer_entry.js.map +1 -1
- package/docs/native-browser-testing.md +11 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/navigation/index.ts"],"sourcesContent":["import { emitRendererTrace } from '../tracing/index.js';\n\nconst NAVIGATION_SYMBOL = Symbol.for('@noego/wood.navigation');\nconst HISTORY_STATE_MARKER = '__wood_navigation_state__';\n\nexport interface NavigationEntry {\n page: string;\n params: Record<string, string>;\n query: Record<string, string>;\n options: NavigationOptions;\n}\n\nimport type { NavigationOptions } from './layout_preservation.js';\nexport type { NavigationOptions } from './layout_preservation.js';\n\ntype NavigationHistoryState = NavigationEntry & {\n [HISTORY_STATE_MARKER]: true;\n};\n\ntype NavigationListener = (entry: NavigationEntry | null) => void;\n\nexport class Navigation {\n private entries: NavigationEntry[] = [];\n private index = -1;\n private listeners = new Set<NavigationListener>();\n\n getCurrent(): NavigationEntry | null {\n if (this.index < 0 || this.index >= this.entries.length) {\n return null;\n }\n return this.cloneEntry(this.entries[this.index]);\n }\n\n getPages(): NavigationEntry[] {\n return this.entries.map((entry) => this.cloneEntry(entry));\n }\n\n getParams(): Record<string, string> {\n const current = this.getCurrent();\n if (!current) {\n return {};\n }\n return { ...current.params };\n }\n\n replace(\n page: string,\n params: Record<string, string> = {},\n query: Record<string, string> = {},\n options: NavigationOptions = {},\n ): NavigationEntry {\n const entry = this.createEntry(page, params, query, options);\n\n if (this.index < 0) {\n this.entries.push(entry);\n this.index = 0;\n } else {\n this.entries[this.index] = entry;\n }\n\n this.writeWindowHistory('replaceState', entry);\n this.notify();\n emitRendererTrace('info', {\n source: 'wood.navigation',\n type: 'navigation.replace',\n payload: {\n page: entry.page,\n params: entry.params,\n query: entry.query,\n options: entry.options,\n },\n });\n return this.cloneEntry(entry);\n }\n\n go(\n page: string,\n params: Record<string, string> = {},\n query: Record<string, string> = {},\n options: NavigationOptions = {},\n ): NavigationEntry {\n const entry = this.createEntry(page, params, query, options);\n if (this.index < this.entries.length - 1) {\n this.entries = this.entries.slice(0, this.index + 1);\n }\n this.entries.push(entry);\n this.index = this.entries.length - 1;\n\n this.writeWindowHistory('pushState', entry);\n this.notify();\n emitRendererTrace('info', {\n source: 'wood.navigation',\n type: 'navigation.go',\n payload: {\n page: entry.page,\n params: entry.params,\n query: entry.query,\n options: entry.options,\n },\n });\n return this.cloneEntry(entry);\n }\n\n goto(delta: number): NavigationEntry | null {\n return this.moveCursor(delta);\n }\n\n goBack(): NavigationEntry | null {\n return this.goto(-1);\n }\n\n goForward(): NavigationEntry | null {\n return this.goto(1);\n }\n\n subscribe(listener: NavigationListener): () => void {\n this.listeners.add(listener);\n listener(this.getCurrent());\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n private moveCursor(delta: number): NavigationEntry | null {\n if (delta === 0) {\n return this.getCurrent();\n }\n\n const nextIndex = this.index + delta;\n if (nextIndex < 0 || nextIndex >= this.entries.length) {\n return this.getCurrent();\n }\n\n this.index = nextIndex;\n const entry = this.entries[this.index];\n this.writeWindowHistory('replaceState', entry);\n this.notify();\n emitRendererTrace('info', {\n source: 'wood.navigation',\n type: 'navigation.goto',\n payload: {\n delta,\n page: entry.page,\n },\n });\n return this.cloneEntry(entry);\n }\n\n private notify(): void {\n const current = this.getCurrent();\n for (const listener of this.listeners) {\n listener(current);\n }\n }\n\n private createEntry(\n page: string,\n params: Record<string, string>,\n query: Record<string, string>,\n options: NavigationOptions,\n ): NavigationEntry {\n return {\n page,\n params: this.normalizeRecord(params),\n query: this.normalizeRecord(query),\n options: { ...options },\n };\n }\n\n private cloneEntry(entry: NavigationEntry): NavigationEntry {\n return {\n page: entry.page,\n params: { ...entry.params },\n query: { ...entry.query },\n options: { ...entry.options },\n };\n }\n\n private normalizeRecord(input: Record<string, string>): Record<string, string> {\n const output: Record<string, string> = {};\n for (const [key, value] of Object.entries(input ?? {})) {\n output[String(key)] = String(value);\n }\n return output;\n }\n\n private writeWindowHistory(\n mode: 'pushState' | 'replaceState',\n entry: NavigationEntry,\n ): void {\n if (typeof window === 'undefined') {\n return;\n }\n\n const state: NavigationHistoryState = {\n [HISTORY_STATE_MARKER]: true,\n page: entry.page,\n params: { ...entry.params },\n query: { ...entry.query },\n options: { ...entry.options },\n };\n\n window.history[mode](state, '');\n }\n}\n\ntype GlobalWithNavigation = typeof globalThis & {\n [NAVIGATION_SYMBOL]?: Navigation;\n};\n\nfunction createNavigationInstance(): Navigation {\n return new Navigation();\n}\n\nexport function getNavigation(): Navigation {\n const globalObj = globalThis as GlobalWithNavigation;\n if (!globalObj[NAVIGATION_SYMBOL]) {\n globalObj[NAVIGATION_SYMBOL] = createNavigationInstance();\n }\n return globalObj[NAVIGATION_SYMBOL];\n}\n\nexport function goto(\n delta: number,\n): NavigationEntry | null {\n return getNavigation().goto(delta);\n}\n\nexport function go(\n page: string,\n params: Record<string, string> = {},\n query: Record<string, string> = {},\n options: NavigationOptions = {},\n): NavigationEntry {\n return getNavigation().go(page, params, query, options);\n}\n\nexport function goback(): NavigationEntry | null {\n return goto(-1);\n}\n\n/** Test-only helper to clear the navigation singleton. */\nexport function clearNavigationForTests(): void {\n const globalObj = globalThis as GlobalWithNavigation;\n delete globalObj[NAVIGATION_SYMBOL];\n}\n\n// Dev/test-only automation introspection surface (Axe AXE-WP-02).\n// Benign import cycle: automation_introspection uses getNavigation lazily.\n// NOTE: keep these re-exports single-line — the tsup extension-rewrite plugin\n// only rewrites single-line import/export specifiers.\nexport { installAutomationIntrospection, WOOD_AUTOMATION_GLOBAL_KEY } from './automation_introspection.js';\nexport type { WoodAutomationSnapshot, WoodAutomationEvent, WoodAutomationIntrospection, InstallAutomationIntrospectionOptions } from './automation_introspection.js';\nexport { computePreservedLayoutDepth } from './layout_preservation.js';\nexport type { LayoutStack } from './layout_preservation.js';\n// Shared page/layout data-loader orchestration for the generated renderer app.\nexport { createLoaderRequest, initializeArgument, initializeController, runViewLoaders, assertDataLoader, NO_LOADERS } from '../loader/loader_orchestration.js';\nexport type { DataLoader, LoadedData, RouteInput, ViewLoaderResult, ViewLoaderSet } from '../loader/loader_orchestration.js';\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/navigation/index.ts"],"sourcesContent":["import { emitRendererTrace } from '../tracing/index.js';\n\nconst NAVIGATION_SYMBOL = Symbol.for('@noego/wood.navigation');\nconst HISTORY_STATE_MARKER = '__wood_navigation_state__';\n\nexport interface NavigationEntry {\n page: string;\n params: Record<string, string>;\n query: Record<string, string>;\n options: NavigationOptions;\n}\n\nimport type { NavigationOptions } from './layout_preservation.js';\nexport type { NavigationOptions } from './layout_preservation.js';\n\ntype NavigationHistoryState = NavigationEntry & {\n [HISTORY_STATE_MARKER]: true;\n};\n\n/** Validate persisted route data before a new document uses it for bootstrap. */\nexport function readNavigationHistory(state: unknown): Pick<NavigationEntry, 'page' | 'params' | 'query'> | null {\n if (!state || typeof state !== 'object' || Array.isArray(state)) return null;\n const value = state as Record<string, unknown>;\n if (value[HISTORY_STATE_MARKER] !== true || typeof value.page !== 'string' || !value.page.trim()) return null;\n const record = (input: unknown): input is Record<string, string> => {\n if (!input || typeof input !== 'object' || Array.isArray(input)) return false;\n const prototype = Object.getPrototypeOf(input);\n return (prototype === Object.prototype || prototype === null) && Object.values(input).every(item => typeof item === 'string');\n };\n if (!record(value.params) || !record(value.query)) return null;\n return {page: value.page, params: {...value.params}, query: {...value.query}};\n}\n\ntype NavigationListener = (entry: NavigationEntry | null) => void;\n\nexport class Navigation {\n private entries: NavigationEntry[] = [];\n private index = -1;\n private listeners = new Set<NavigationListener>();\n\n getCurrent(): NavigationEntry | null {\n if (this.index < 0 || this.index >= this.entries.length) {\n return null;\n }\n return this.cloneEntry(this.entries[this.index]);\n }\n\n getPages(): NavigationEntry[] {\n return this.entries.map((entry) => this.cloneEntry(entry));\n }\n\n getParams(): Record<string, string> {\n const current = this.getCurrent();\n if (!current) {\n return {};\n }\n return { ...current.params };\n }\n\n replace(\n page: string,\n params: Record<string, string> = {},\n query: Record<string, string> = {},\n options: NavigationOptions = {},\n ): NavigationEntry {\n const entry = this.createEntry(page, params, query, options);\n\n if (this.index < 0) {\n this.entries.push(entry);\n this.index = 0;\n } else {\n this.entries[this.index] = entry;\n }\n\n this.writeWindowHistory('replaceState', entry);\n this.notify();\n emitRendererTrace('info', {\n source: 'wood.navigation',\n type: 'navigation.replace',\n payload: {\n page: entry.page,\n params: entry.params,\n query: entry.query,\n options: entry.options,\n },\n });\n return this.cloneEntry(entry);\n }\n\n go(\n page: string,\n params: Record<string, string> = {},\n query: Record<string, string> = {},\n options: NavigationOptions = {},\n ): NavigationEntry {\n const entry = this.createEntry(page, params, query, options);\n if (this.index < this.entries.length - 1) {\n this.entries = this.entries.slice(0, this.index + 1);\n }\n this.entries.push(entry);\n this.index = this.entries.length - 1;\n\n this.writeWindowHistory('pushState', entry);\n this.notify();\n emitRendererTrace('info', {\n source: 'wood.navigation',\n type: 'navigation.go',\n payload: {\n page: entry.page,\n params: entry.params,\n query: entry.query,\n options: entry.options,\n },\n });\n return this.cloneEntry(entry);\n }\n\n goto(delta: number): NavigationEntry | null {\n return this.moveCursor(delta);\n }\n\n goBack(): NavigationEntry | null {\n return this.goto(-1);\n }\n\n goForward(): NavigationEntry | null {\n return this.goto(1);\n }\n\n subscribe(listener: NavigationListener): () => void {\n this.listeners.add(listener);\n listener(this.getCurrent());\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n private moveCursor(delta: number): NavigationEntry | null {\n if (delta === 0) {\n return this.getCurrent();\n }\n\n const nextIndex = this.index + delta;\n if (nextIndex < 0 || nextIndex >= this.entries.length) {\n return this.getCurrent();\n }\n\n this.index = nextIndex;\n const entry = this.entries[this.index];\n this.writeWindowHistory('replaceState', entry);\n this.notify();\n emitRendererTrace('info', {\n source: 'wood.navigation',\n type: 'navigation.goto',\n payload: {\n delta,\n page: entry.page,\n },\n });\n return this.cloneEntry(entry);\n }\n\n private notify(): void {\n const current = this.getCurrent();\n for (const listener of this.listeners) {\n listener(current);\n }\n }\n\n private createEntry(\n page: string,\n params: Record<string, string>,\n query: Record<string, string>,\n options: NavigationOptions,\n ): NavigationEntry {\n return {\n page,\n params: this.normalizeRecord(params),\n query: this.normalizeRecord(query),\n options: { ...options },\n };\n }\n\n private cloneEntry(entry: NavigationEntry): NavigationEntry {\n return {\n page: entry.page,\n params: { ...entry.params },\n query: { ...entry.query },\n options: { ...entry.options },\n };\n }\n\n private normalizeRecord(input: Record<string, string>): Record<string, string> {\n const output: Record<string, string> = {};\n for (const [key, value] of Object.entries(input ?? {})) {\n output[String(key)] = String(value);\n }\n return output;\n }\n\n private writeWindowHistory(\n mode: 'pushState' | 'replaceState',\n entry: NavigationEntry,\n ): void {\n if (typeof window === 'undefined') {\n return;\n }\n\n const state: NavigationHistoryState = {\n [HISTORY_STATE_MARKER]: true,\n page: entry.page,\n params: { ...entry.params },\n query: { ...entry.query },\n options: { ...entry.options },\n };\n\n window.history[mode](state, '');\n }\n}\n\ntype GlobalWithNavigation = typeof globalThis & {\n [NAVIGATION_SYMBOL]?: Navigation;\n};\n\nfunction createNavigationInstance(): Navigation {\n return new Navigation();\n}\n\nexport function getNavigation(): Navigation {\n const globalObj = globalThis as GlobalWithNavigation;\n if (!globalObj[NAVIGATION_SYMBOL]) {\n globalObj[NAVIGATION_SYMBOL] = createNavigationInstance();\n }\n return globalObj[NAVIGATION_SYMBOL];\n}\n\nexport function goto(\n delta: number,\n): NavigationEntry | null {\n return getNavigation().goto(delta);\n}\n\nexport function go(\n page: string,\n params: Record<string, string> = {},\n query: Record<string, string> = {},\n options: NavigationOptions = {},\n): NavigationEntry {\n return getNavigation().go(page, params, query, options);\n}\n\nexport function goback(): NavigationEntry | null {\n return goto(-1);\n}\n\n/** Test-only helper to clear the navigation singleton. */\nexport function clearNavigationForTests(): void {\n const globalObj = globalThis as GlobalWithNavigation;\n delete globalObj[NAVIGATION_SYMBOL];\n}\n\n// Dev/test-only automation introspection surface (Axe AXE-WP-02).\n// Benign import cycle: automation_introspection uses getNavigation lazily.\n// NOTE: keep these re-exports single-line — the tsup extension-rewrite plugin\n// only rewrites single-line import/export specifiers.\nexport { installAutomationIntrospection, WOOD_AUTOMATION_GLOBAL_KEY } from './automation_introspection.js';\nexport type { WoodAutomationSnapshot, WoodAutomationEvent, WoodAutomationIntrospection, InstallAutomationIntrospectionOptions } from './automation_introspection.js';\nexport { computePreservedLayoutDepth } from './layout_preservation.js';\nexport type { LayoutStack } from './layout_preservation.js';\n// Shared page/layout data-loader orchestration for the generated renderer app.\nexport { createLoaderRequest, initializeArgument, initializeController, runViewLoaders, assertDataLoader, NO_LOADERS } from '../loader/loader_orchestration.js';\nexport type { DataLoader, LoadedData, RouteInput, ViewLoaderResult, ViewLoaderSet } from '../loader/loader_orchestration.js';\n"],"mappings":"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","names":[]}
|
package/dist/testing/browser.cjs
CHANGED
|
@@ -32,6 +32,7 @@ __export(browser_exports, {
|
|
|
32
32
|
createBrowserBridgeFixture: () => createBrowserBridgeFixture,
|
|
33
33
|
createBrowserFixture: () => createBrowserFixture,
|
|
34
34
|
createWoodBrowserResolver: () => createWoodBrowserResolver,
|
|
35
|
+
isInsideRoot: () => isInsideRoot,
|
|
35
36
|
loadSveltePlugin: () => loadSveltePlugin,
|
|
36
37
|
startSharedBrowserViteServer: () => startSharedBrowserViteServer
|
|
37
38
|
});
|
|
@@ -261,6 +262,13 @@ function resolvePackageDir(rootDir, packageName) {
|
|
|
261
262
|
const packageJson = resolvePackageModule(rootDir, `${packageName}/package.json`);
|
|
262
263
|
return packageJson ? import_node_path.default.dirname(packageJson) : null;
|
|
263
264
|
}
|
|
265
|
+
function isInsideRoot(rootDir, importer) {
|
|
266
|
+
const withoutQuery = importer.split("?")[0] ?? importer;
|
|
267
|
+
const fsPath = withoutQuery.startsWith("/@fs/") ? `/${withoutQuery.slice("/@fs/".length).replace(/^\/+/, "")}` : withoutQuery;
|
|
268
|
+
const root = import_node_path.default.resolve(rootDir).replace(/\\/g, "/");
|
|
269
|
+
const candidate = import_node_path.default.resolve(fsPath).replace(/\\/g, "/");
|
|
270
|
+
return candidate === root || candidate.startsWith(`${root}/`);
|
|
271
|
+
}
|
|
264
272
|
function createWoodBrowserResolver(rootDir) {
|
|
265
273
|
const sveltePackageDir = resolvePackageDir(rootDir, "svelte");
|
|
266
274
|
const svelteClientEntry = sveltePackageDir ? import_node_path.default.join(sveltePackageDir, "src", "index-client.js") : null;
|
|
@@ -269,8 +277,9 @@ function createWoodBrowserResolver(rootDir) {
|
|
|
269
277
|
return {
|
|
270
278
|
name: "wood-browser-resolver",
|
|
271
279
|
enforce: "pre",
|
|
272
|
-
resolveId(source) {
|
|
280
|
+
resolveId(source, importer) {
|
|
273
281
|
if (source.startsWith("@noego/wood/")) {
|
|
282
|
+
if (importer && isInsideRoot(rootDir, importer)) return null;
|
|
274
283
|
const resolved = resolvePackageModule(rootDir, source);
|
|
275
284
|
const esm = resolved?.endsWith(".cjs") ? resolved.replace(/\.cjs$/, ".js") : resolved;
|
|
276
285
|
return esm && import_node_fs.default.existsSync(esm) ? esm : null;
|
|
@@ -1569,6 +1578,7 @@ async function createBrowserFixture(config = {}) {
|
|
|
1569
1578
|
createBrowserBridgeFixture,
|
|
1570
1579
|
createBrowserFixture,
|
|
1571
1580
|
createWoodBrowserResolver,
|
|
1581
|
+
isInsideRoot,
|
|
1572
1582
|
loadSveltePlugin,
|
|
1573
1583
|
startSharedBrowserViteServer
|
|
1574
1584
|
});
|