@noego/wood 0.2.1 → 0.3.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/dist/codegen/renderer_app_generator.cjs +17 -1
- package/dist/codegen/renderer_app_generator.cjs.map +1 -1
- package/dist/codegen/renderer_app_generator.js +17 -1
- package/dist/codegen/renderer_app_generator.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/navigation/index.cjs +17 -12
- package/dist/navigation/index.cjs.map +1 -1
- package/dist/navigation/index.d.cts +8 -4
- package/dist/navigation/index.d.ts +8 -4
- package/dist/navigation/index.js +17 -12
- package/dist/navigation/index.js.map +1 -1
- package/dist/parser/views_parser.cjs +24 -3
- package/dist/parser/views_parser.cjs.map +1 -1
- package/dist/parser/views_parser.js +24 -3
- package/dist/parser/views_parser.js.map +1 -1
- package/dist/types/views.cjs.map +1 -1
- package/dist/types/views.d.cts +3 -0
- package/dist/types/views.d.ts +3 -0
- package/package.json +1 -1
- package/src/components/NavigationShell.svelte +154 -27
- package/src/components/WoodRecursiveRender.svelte +49 -36
|
@@ -183,6 +183,15 @@ function generateRendererApp(views, options) {
|
|
|
183
183
|
);
|
|
184
184
|
const layoutControllerPaths = `[${normalizedLayoutControllerRefs.map((controllerRef) => controllerRef ? `'${escapeSingleQuoted(controllerRef)}'` : "undefined").join(", ")}]`;
|
|
185
185
|
const layoutControllerClasses = `[${normalizedLayoutControllerRefs.map((controllerRef) => controllerRef ? controllerIdentifiers.get(controllerRef).identifier : "undefined").join(", ")}]`;
|
|
186
|
+
const layoutPreserve = view.layoutPreserve ?? Array.from(
|
|
187
|
+
{ length: view.layouts.length },
|
|
188
|
+
() => false
|
|
189
|
+
);
|
|
190
|
+
if (layoutPreserve.length !== view.layouts.length) {
|
|
191
|
+
throw new Error(
|
|
192
|
+
`Renderer app codegen failed: layout preserve count for view "${key}" does not match layout count.`
|
|
193
|
+
);
|
|
194
|
+
}
|
|
186
195
|
return ` '${escapeSingleQuoted(key)}': {
|
|
187
196
|
key: '${escapeSingleQuoted(key)}',
|
|
188
197
|
windowName: '${escapeSingleQuoted(view.windowName)}',
|
|
@@ -190,6 +199,7 @@ function generateRendererApp(views, options) {
|
|
|
190
199
|
viewPath: '${escapeSingleQuoted(view.viewPath)}',
|
|
191
200
|
layoutPaths: ${JSON.stringify(view.layouts)},
|
|
192
201
|
layoutControllers: ${layoutControllerPaths},
|
|
202
|
+
layoutPreserve: ${JSON.stringify(layoutPreserve)},
|
|
193
203
|
controller: ${controllerPath},
|
|
194
204
|
layoutControllerClasses: ${layoutControllerClasses},
|
|
195
205
|
controllerClass: ${controllerClass},
|
|
@@ -212,6 +222,7 @@ interface GeneratedAppViewEntry {
|
|
|
212
222
|
viewPath: string;
|
|
213
223
|
layoutPaths: string[];
|
|
214
224
|
layoutControllers: Array<string | undefined>;
|
|
225
|
+
layoutPreserve: boolean[];
|
|
215
226
|
controller?: string;
|
|
216
227
|
layoutControllerClasses: Array<any | undefined>;
|
|
217
228
|
controllerClass?: any;
|
|
@@ -294,10 +305,15 @@ async function createViewController(
|
|
|
294
305
|
|
|
295
306
|
async function createLayoutControllers(
|
|
296
307
|
entry: GeneratedAppViewEntry,
|
|
308
|
+
startIndex = 0,
|
|
297
309
|
): Promise<Array<unknown>> {
|
|
298
310
|
const controllers: unknown[] = [];
|
|
299
311
|
|
|
300
|
-
for (let i = 0; i <
|
|
312
|
+
for (let i = 0; i < startIndex; i += 1) {
|
|
313
|
+
controllers.push(undefined);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
for (let i = startIndex; i < entry.layoutControllerClasses.length; i += 1) {
|
|
301
317
|
const LayoutController = entry.layoutControllerClasses[i];
|
|
302
318
|
if (!LayoutController) {
|
|
303
319
|
controllers.push(undefined);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/codegen/renderer_app_generator.ts"],"sourcesContent":["import { existsSync } from 'fs';\nimport path from 'path';\nimport type { ViewDef } from '../types/index.cjs';\n\nexport interface RendererAppGeneratorOptions {\n /** Absolute path to renderer component root (e.g. /app/ui) */\n componentDir: string;\n /** Absolute output directory where generated file will be written */\n outDir: string;\n /** Optional explicit default view key (e.g. \"main.chat\") */\n entryViewKey?: string;\n}\n\nfunction computeImportPath(fromDir: string, toFile: string): string {\n let rel = path.relative(fromDir, toFile);\n\n if (!rel.startsWith('.')) {\n rel = './' + rel;\n }\n\n return rel.replace(/\\\\/g, '/');\n}\n\nfunction resolveFromComponentDir(componentDir: string, fileRef: string): string {\n if (path.isAbsolute(fileRef)) {\n return fileRef;\n }\n\n const normalizedRef = fileRef.replace(/\\\\/g, '/');\n const componentDirName = path.basename(componentDir).replace(/\\\\/g, '/');\n\n if (normalizedRef.startsWith(componentDirName + '/')) {\n const stripped = normalizedRef.slice(componentDirName.length + 1);\n return path.resolve(componentDir, stripped);\n }\n\n return path.resolve(componentDir, normalizedRef);\n}\n\nfunction viewKey(view: ViewDef): string {\n return `${view.windowName}.${view.pageName}`;\n}\n\nfunction toIdentifier(prefix: string, value: string): string {\n const core = value\n .replace(/[^a-zA-Z0-9]+/g, ' ')\n .trim()\n .split(/\\s+/)\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n .join('');\n\n return `${prefix}${core || 'Component'}`;\n}\n\nfunction escapeSingleQuoted(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\nconst CONTROLLER_FILE_SUFFIXES = [\n '.ts',\n '.js',\n '.controller.ts',\n '.controller.js',\n] as const;\n\nconst CONTROLLER_INDEX_CANDIDATES = [\n 'index.ts',\n 'index.js',\n] as const;\n\nfunction resolveControllerFile(controllerRef: string, componentDir: string): string | null {\n const normalized = controllerRef.trim();\n const basePath = resolveFromComponentDir(componentDir, normalized);\n\n if (existsSync(basePath)) {\n return basePath;\n }\n\n if (path.extname(basePath)) {\n return null;\n }\n\n for (const suffix of CONTROLLER_FILE_SUFFIXES) {\n const candidate = basePath + suffix;\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n for (const indexFile of CONTROLLER_INDEX_CANDIDATES) {\n const candidate = path.resolve(basePath, indexFile);\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\nfunction resolveDefaultViewKey(sortedViews: ViewDef[], entryViewKey?: string): string {\n if (sortedViews.length === 0) return '';\n\n const configuredEntry = entryViewKey?.trim();\n if (!configuredEntry) {\n return viewKey(sortedViews[0]);\n }\n\n const availableKeys = sortedViews.map((view) => viewKey(view));\n if (availableKeys.includes(configuredEntry)) {\n return configuredEntry;\n }\n\n throw new Error(\n `Renderer entry \"${configuredEntry}\" was not found in parsed views. Available view keys: ${availableKeys.join(', ')}`,\n );\n}\n\nexport function generateRendererApp(\n views: ViewDef[],\n options: RendererAppGeneratorOptions,\n): string {\n const sortedViews = [...views].sort((a, b) => viewKey(a).localeCompare(viewKey(b)));\n const defaultViewKey = resolveDefaultViewKey(sortedViews, options.entryViewKey);\n\n const importLines: string[] = [];\n const viewIdentifiers = new Map<string, string>();\n const layoutIdentifiers = new Map<string, string>();\n const controllerIdentifiers = new Map<string, { identifier: string; importPath: string }>();\n const usedNames = new Set<string>();\n\n const allocateName = (prefix: string, filePath: string): string => {\n const base = toIdentifier(prefix, filePath);\n let name = base;\n let suffix = 2;\n while (usedNames.has(name)) {\n name = `${base}${suffix}`;\n suffix += 1;\n }\n usedNames.add(name);\n return name;\n };\n\n const ensureControllerImported = (controllerRef: string, owningViewKey: string): void => {\n if (controllerIdentifiers.has(controllerRef)) return;\n\n const resolvedControllerFile = resolveControllerFile(controllerRef, options.componentDir);\n if (!resolvedControllerFile) {\n throw new Error(\n `Renderer app codegen failed: controller \"${controllerRef}\" for view \"${owningViewKey}\" was not found. ` +\n 'Controller must point to an existing file with a default exported class.',\n );\n }\n\n const identifier = allocateName('PageController', controllerRef);\n const importPath = computeImportPath(options.outDir, resolvedControllerFile);\n controllerIdentifiers.set(controllerRef, { identifier, importPath });\n importLines.push(`import ${identifier} from '${importPath}';`);\n };\n\n for (const view of sortedViews) {\n if (!viewIdentifiers.has(view.viewPath)) {\n const identifier = allocateName('View', view.viewPath);\n viewIdentifiers.set(view.viewPath, identifier);\n const abs = resolveFromComponentDir(options.componentDir, view.viewPath);\n const importPath = computeImportPath(options.outDir, abs);\n importLines.push(`import ${identifier} from '${importPath}';`);\n }\n\n for (const layoutPath of view.layouts) {\n if (layoutIdentifiers.has(layoutPath)) continue;\n const identifier = allocateName('Layout', layoutPath);\n layoutIdentifiers.set(layoutPath, identifier);\n const abs = resolveFromComponentDir(options.componentDir, layoutPath);\n const importPath = computeImportPath(options.outDir, abs);\n importLines.push(`import ${identifier} from '${importPath}';`);\n }\n\n if (view.controller) {\n ensureControllerImported(view.controller, viewKey(view));\n }\n\n for (const layoutController of view.layoutControllers ?? []) {\n if (!layoutController) continue;\n ensureControllerImported(layoutController, viewKey(view));\n }\n }\n\n const manifestEntries = sortedViews.map((view) => {\n const key = viewKey(view);\n const viewIdentifier = viewIdentifiers.get(view.viewPath)!;\n const layoutList = view.layouts.map((layoutPath) => layoutIdentifiers.get(layoutPath)!);\n const controllerPath = view.controller ? `'${escapeSingleQuoted(view.controller)}'` : 'undefined';\n const controllerClass = view.controller\n ? controllerIdentifiers.get(view.controller)!.identifier\n : 'undefined';\n const layoutControllerRefs = view.layoutControllers;\n if (layoutControllerRefs && layoutControllerRefs.length !== view.layouts.length) {\n throw new Error(\n `Renderer app codegen failed: layout controller count for view \"${key}\" does not match layout count.`,\n );\n }\n const normalizedLayoutControllerRefs = layoutControllerRefs ?? Array.from(\n { length: view.layouts.length },\n () => undefined,\n );\n const layoutControllerPaths = `[${normalizedLayoutControllerRefs\n .map((controllerRef) => (controllerRef ? `'${escapeSingleQuoted(controllerRef)}'` : 'undefined'))\n .join(', ')}]`;\n const layoutControllerClasses = `[${normalizedLayoutControllerRefs\n .map((controllerRef) => (controllerRef ? controllerIdentifiers.get(controllerRef)!.identifier : 'undefined'))\n .join(', ')}]`;\n\n return ` '${escapeSingleQuoted(key)}': {\n key: '${escapeSingleQuoted(key)}',\n windowName: '${escapeSingleQuoted(view.windowName)}',\n pageName: '${escapeSingleQuoted(view.pageName)}',\n viewPath: '${escapeSingleQuoted(view.viewPath)}',\n layoutPaths: ${JSON.stringify(view.layouts)},\n layoutControllers: ${layoutControllerPaths},\n controller: ${controllerPath},\n layoutControllerClasses: ${layoutControllerClasses},\n controllerClass: ${controllerClass},\n view: ${viewIdentifier},\n layouts: [${layoutList.join(', ')}],\n },`;\n });\n\n return `// AUTO-GENERATED by @noego/wood -- do not edit\nimport { mount } from 'svelte';\nimport { App, getApp, getContainer } from '@noego/wood/client';\nimport { Navigation, getNavigation } from '@noego/wood/navigation';\nimport { Ipc, getIpc } from '@noego/wood/ipc';\nimport NavigationShell from '@noego/wood/navigation-shell';\n${importLines.join('\\n')}\n\ninterface GeneratedAppViewEntry {\n key: string;\n windowName: string;\n pageName: string;\n viewPath: string;\n layoutPaths: string[];\n layoutControllers: Array<string | undefined>;\n controller?: string;\n layoutControllerClasses: Array<any | undefined>;\n controllerClass?: any;\n view: any;\n layouts: any[];\n}\n\nconst VIEW_MANIFEST: Record<string, GeneratedAppViewEntry> = {\n${manifestEntries.join('\\n')}\n};\n\nfunction getViewManifestEntry(viewKey: string): GeneratedAppViewEntry | null {\n return VIEW_MANIFEST[viewKey] ?? null;\n}\n\ninterface WoodScopedContainer {\n get(token: any): unknown | Promise<unknown>;\n registerClass?(token: any): void;\n registerFunction?(\n token: any,\n resolver: (...args: any[]) => unknown,\n options?: Record<string, unknown>,\n ): void;\n}\n\ninterface WoodContainer extends WoodScopedContainer {\n extend?(): WoodScopedContainer;\n}\n\nfunction createScopedContainer(): WoodScopedContainer {\n const container = getContainer() as WoodContainer;\n if (typeof container.extend !== 'function') {\n throw new Error('Wood client container does not support extend().');\n }\n\n const scopedContainer = container.extend();\n\n if (!scopedContainer || typeof scopedContainer.get !== 'function') {\n throw new Error('Wood client container does not support get().');\n }\n\n if (typeof scopedContainer.registerFunction === 'function') {\n scopedContainer.registerFunction(Navigation, () => getNavigation());\n scopedContainer.registerFunction(App, () => getApp());\n scopedContainer.registerFunction(Ipc, () => getIpc());\n }\n\n return scopedContainer as WoodScopedContainer;\n}\n\nasync function resolveController(\n entry: GeneratedAppViewEntry,\n ControllerClass: any,\n contextLabel: string,\n): Promise<unknown> {\n const scopedContainer = createScopedContainer();\n\n if (typeof ControllerClass !== 'function') {\n throw new Error(\n \\`Controller for \\${contextLabel} in view \"\\${entry.key}\" is invalid. Expected a default exported class.\\`,\n );\n }\n\n if (typeof scopedContainer.registerClass === 'function') {\n scopedContainer.registerClass(ControllerClass);\n }\n\n return await scopedContainer.get(ControllerClass);\n}\n\nasync function createViewController(\n entry: GeneratedAppViewEntry,\n): Promise<unknown> {\n if (!entry.controllerClass) {\n return undefined;\n }\n\n return await resolveController(entry, entry.controllerClass, 'page');\n}\n\nasync function createLayoutControllers(\n entry: GeneratedAppViewEntry,\n): Promise<Array<unknown>> {\n const controllers: unknown[] = [];\n\n for (let i = 0; i < entry.layoutControllerClasses.length; i += 1) {\n const LayoutController = entry.layoutControllerClasses[i];\n if (!LayoutController) {\n controllers.push(undefined);\n continue;\n }\n const controller = await resolveController(\n entry,\n LayoutController,\n \\`layout[\\${i}]\\`,\n );\n controllers.push(controller);\n }\n\n return controllers;\n}\n\nconst DEFAULT_VIEW_KEY = '${escapeSingleQuoted(defaultViewKey)}';\n\ntype WoodWindowBootstrapInfo = {\n ok?: boolean;\n windowId?: string;\n defaultRoute?: string;\n};\n\ntype WoodBootstrapBridgeLike = {\n __window?: {\n current?: () => Promise<WoodWindowBootstrapInfo>;\n };\n};\n\nfunction getWoodBridge(): WoodBootstrapBridgeLike | null {\n const globalObj = globalThis as typeof globalThis & {\n __NOEGO_WOOD_BRIDGE__?: unknown;\n window?: {\n __NOEGO_WOOD_BRIDGE__?: unknown;\n };\n };\n\n const bridge = globalObj.__NOEGO_WOOD_BRIDGE__ ?? globalObj.window?.__NOEGO_WOOD_BRIDGE__;\n if (!bridge || typeof bridge !== 'object') {\n return null;\n }\n\n return bridge as WoodBootstrapBridgeLike;\n}\n\nasync function resolveInitialEntry(): Promise<GeneratedAppViewEntry> {\n if (!DEFAULT_VIEW_KEY) {\n throw new Error('No views available in renderer manifest. Define at least one view in renderer OpenAPI YAML.');\n }\n\n const bridge = getWoodBridge();\n const bootstrapWindow = await bridge?.__window?.current?.();\n const requestedRoute = bootstrapWindow?.defaultRoute;\n\n if (requestedRoute) {\n const routeEntry = getViewManifestEntry(requestedRoute);\n if (routeEntry) {\n return routeEntry;\n }\n }\n\n const entry = getViewManifestEntry(DEFAULT_VIEW_KEY);\n if (!entry) {\n throw new Error(\\`Default view \"\\${DEFAULT_VIEW_KEY}\" is missing from generated view manifest.\\`);\n }\n\n return entry;\n}\n\nexport async function app(target: Element) {\n const entry = await resolveInitialEntry();\n\n getNavigation().replace(entry.key, {}, {});\n const controller = await createViewController(entry);\n const layoutControllers = await createLayoutControllers(entry);\n\n return mount(NavigationShell, {\n target,\n props: {\n manifest: VIEW_MANIFEST,\n initialEntry: entry,\n initialController: controller,\n initialLayoutControllers: layoutControllers,\n createViewControllerFn: createViewController,\n createLayoutControllersFn: createLayoutControllers,\n getViewManifestEntryFn: getViewManifestEntry,\n },\n });\n}\n`;\n}\n"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BA8FA,mBAAmB,cAAc,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2E9D;","names":["path"]}
|
|
1
|
+
{"version":3,"sources":["../../src/codegen/renderer_app_generator.ts"],"sourcesContent":["import { existsSync } from 'fs';\nimport path from 'path';\nimport type { ViewDef } from '../types/index.cjs';\n\nexport interface RendererAppGeneratorOptions {\n /** Absolute path to renderer component root (e.g. /app/ui) */\n componentDir: string;\n /** Absolute output directory where generated file will be written */\n outDir: string;\n /** Optional explicit default view key (e.g. \"main.chat\") */\n entryViewKey?: string;\n}\n\nfunction computeImportPath(fromDir: string, toFile: string): string {\n let rel = path.relative(fromDir, toFile);\n\n if (!rel.startsWith('.')) {\n rel = './' + rel;\n }\n\n return rel.replace(/\\\\/g, '/');\n}\n\nfunction resolveFromComponentDir(componentDir: string, fileRef: string): string {\n if (path.isAbsolute(fileRef)) {\n return fileRef;\n }\n\n const normalizedRef = fileRef.replace(/\\\\/g, '/');\n const componentDirName = path.basename(componentDir).replace(/\\\\/g, '/');\n\n if (normalizedRef.startsWith(componentDirName + '/')) {\n const stripped = normalizedRef.slice(componentDirName.length + 1);\n return path.resolve(componentDir, stripped);\n }\n\n return path.resolve(componentDir, normalizedRef);\n}\n\nfunction viewKey(view: ViewDef): string {\n return `${view.windowName}.${view.pageName}`;\n}\n\nfunction toIdentifier(prefix: string, value: string): string {\n const core = value\n .replace(/[^a-zA-Z0-9]+/g, ' ')\n .trim()\n .split(/\\s+/)\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n .join('');\n\n return `${prefix}${core || 'Component'}`;\n}\n\nfunction escapeSingleQuoted(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\nconst CONTROLLER_FILE_SUFFIXES = [\n '.ts',\n '.js',\n '.controller.ts',\n '.controller.js',\n] as const;\n\nconst CONTROLLER_INDEX_CANDIDATES = [\n 'index.ts',\n 'index.js',\n] as const;\n\nfunction resolveControllerFile(controllerRef: string, componentDir: string): string | null {\n const normalized = controllerRef.trim();\n const basePath = resolveFromComponentDir(componentDir, normalized);\n\n if (existsSync(basePath)) {\n return basePath;\n }\n\n if (path.extname(basePath)) {\n return null;\n }\n\n for (const suffix of CONTROLLER_FILE_SUFFIXES) {\n const candidate = basePath + suffix;\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n for (const indexFile of CONTROLLER_INDEX_CANDIDATES) {\n const candidate = path.resolve(basePath, indexFile);\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\nfunction resolveDefaultViewKey(sortedViews: ViewDef[], entryViewKey?: string): string {\n if (sortedViews.length === 0) return '';\n\n const configuredEntry = entryViewKey?.trim();\n if (!configuredEntry) {\n return viewKey(sortedViews[0]);\n }\n\n const availableKeys = sortedViews.map((view) => viewKey(view));\n if (availableKeys.includes(configuredEntry)) {\n return configuredEntry;\n }\n\n throw new Error(\n `Renderer entry \"${configuredEntry}\" was not found in parsed views. Available view keys: ${availableKeys.join(', ')}`,\n );\n}\n\nexport function generateRendererApp(\n views: ViewDef[],\n options: RendererAppGeneratorOptions,\n): string {\n const sortedViews = [...views].sort((a, b) => viewKey(a).localeCompare(viewKey(b)));\n const defaultViewKey = resolveDefaultViewKey(sortedViews, options.entryViewKey);\n\n const importLines: string[] = [];\n const viewIdentifiers = new Map<string, string>();\n const layoutIdentifiers = new Map<string, string>();\n const controllerIdentifiers = new Map<string, { identifier: string; importPath: string }>();\n const usedNames = new Set<string>();\n\n const allocateName = (prefix: string, filePath: string): string => {\n const base = toIdentifier(prefix, filePath);\n let name = base;\n let suffix = 2;\n while (usedNames.has(name)) {\n name = `${base}${suffix}`;\n suffix += 1;\n }\n usedNames.add(name);\n return name;\n };\n\n const ensureControllerImported = (controllerRef: string, owningViewKey: string): void => {\n if (controllerIdentifiers.has(controllerRef)) return;\n\n const resolvedControllerFile = resolveControllerFile(controllerRef, options.componentDir);\n if (!resolvedControllerFile) {\n throw new Error(\n `Renderer app codegen failed: controller \"${controllerRef}\" for view \"${owningViewKey}\" was not found. ` +\n 'Controller must point to an existing file with a default exported class.',\n );\n }\n\n const identifier = allocateName('PageController', controllerRef);\n const importPath = computeImportPath(options.outDir, resolvedControllerFile);\n controllerIdentifiers.set(controllerRef, { identifier, importPath });\n importLines.push(`import ${identifier} from '${importPath}';`);\n };\n\n for (const view of sortedViews) {\n if (!viewIdentifiers.has(view.viewPath)) {\n const identifier = allocateName('View', view.viewPath);\n viewIdentifiers.set(view.viewPath, identifier);\n const abs = resolveFromComponentDir(options.componentDir, view.viewPath);\n const importPath = computeImportPath(options.outDir, abs);\n importLines.push(`import ${identifier} from '${importPath}';`);\n }\n\n for (const layoutPath of view.layouts) {\n if (layoutIdentifiers.has(layoutPath)) continue;\n const identifier = allocateName('Layout', layoutPath);\n layoutIdentifiers.set(layoutPath, identifier);\n const abs = resolveFromComponentDir(options.componentDir, layoutPath);\n const importPath = computeImportPath(options.outDir, abs);\n importLines.push(`import ${identifier} from '${importPath}';`);\n }\n\n if (view.controller) {\n ensureControllerImported(view.controller, viewKey(view));\n }\n\n for (const layoutController of view.layoutControllers ?? []) {\n if (!layoutController) continue;\n ensureControllerImported(layoutController, viewKey(view));\n }\n }\n\n const manifestEntries = sortedViews.map((view) => {\n const key = viewKey(view);\n const viewIdentifier = viewIdentifiers.get(view.viewPath)!;\n const layoutList = view.layouts.map((layoutPath) => layoutIdentifiers.get(layoutPath)!);\n const controllerPath = view.controller ? `'${escapeSingleQuoted(view.controller)}'` : 'undefined';\n const controllerClass = view.controller\n ? controllerIdentifiers.get(view.controller)!.identifier\n : 'undefined';\n const layoutControllerRefs = view.layoutControllers;\n if (layoutControllerRefs && layoutControllerRefs.length !== view.layouts.length) {\n throw new Error(\n `Renderer app codegen failed: layout controller count for view \"${key}\" does not match layout count.`,\n );\n }\n const normalizedLayoutControllerRefs = layoutControllerRefs ?? Array.from(\n { length: view.layouts.length },\n () => undefined,\n );\n const layoutControllerPaths = `[${normalizedLayoutControllerRefs\n .map((controllerRef) => (controllerRef ? `'${escapeSingleQuoted(controllerRef)}'` : 'undefined'))\n .join(', ')}]`;\n const layoutControllerClasses = `[${normalizedLayoutControllerRefs\n .map((controllerRef) => (controllerRef ? controllerIdentifiers.get(controllerRef)!.identifier : 'undefined'))\n .join(', ')}]`;\n const layoutPreserve = view.layoutPreserve ?? Array.from(\n { length: view.layouts.length },\n () => false,\n );\n if (layoutPreserve.length !== view.layouts.length) {\n throw new Error(\n `Renderer app codegen failed: layout preserve count for view \"${key}\" does not match layout count.`,\n );\n }\n\n return ` '${escapeSingleQuoted(key)}': {\n key: '${escapeSingleQuoted(key)}',\n windowName: '${escapeSingleQuoted(view.windowName)}',\n pageName: '${escapeSingleQuoted(view.pageName)}',\n viewPath: '${escapeSingleQuoted(view.viewPath)}',\n layoutPaths: ${JSON.stringify(view.layouts)},\n layoutControllers: ${layoutControllerPaths},\n layoutPreserve: ${JSON.stringify(layoutPreserve)},\n controller: ${controllerPath},\n layoutControllerClasses: ${layoutControllerClasses},\n controllerClass: ${controllerClass},\n view: ${viewIdentifier},\n layouts: [${layoutList.join(', ')}],\n },`;\n });\n\n return `// AUTO-GENERATED by @noego/wood -- do not edit\nimport { mount } from 'svelte';\nimport { App, getApp, getContainer } from '@noego/wood/client';\nimport { Navigation, getNavigation } from '@noego/wood/navigation';\nimport { Ipc, getIpc } from '@noego/wood/ipc';\nimport NavigationShell from '@noego/wood/navigation-shell';\n${importLines.join('\\n')}\n\ninterface GeneratedAppViewEntry {\n key: string;\n windowName: string;\n pageName: string;\n viewPath: string;\n layoutPaths: string[];\n layoutControllers: Array<string | undefined>;\n layoutPreserve: boolean[];\n controller?: string;\n layoutControllerClasses: Array<any | undefined>;\n controllerClass?: any;\n view: any;\n layouts: any[];\n}\n\nconst VIEW_MANIFEST: Record<string, GeneratedAppViewEntry> = {\n${manifestEntries.join('\\n')}\n};\n\nfunction getViewManifestEntry(viewKey: string): GeneratedAppViewEntry | null {\n return VIEW_MANIFEST[viewKey] ?? null;\n}\n\ninterface WoodScopedContainer {\n get(token: any): unknown | Promise<unknown>;\n registerClass?(token: any): void;\n registerFunction?(\n token: any,\n resolver: (...args: any[]) => unknown,\n options?: Record<string, unknown>,\n ): void;\n}\n\ninterface WoodContainer extends WoodScopedContainer {\n extend?(): WoodScopedContainer;\n}\n\nfunction createScopedContainer(): WoodScopedContainer {\n const container = getContainer() as WoodContainer;\n if (typeof container.extend !== 'function') {\n throw new Error('Wood client container does not support extend().');\n }\n\n const scopedContainer = container.extend();\n\n if (!scopedContainer || typeof scopedContainer.get !== 'function') {\n throw new Error('Wood client container does not support get().');\n }\n\n if (typeof scopedContainer.registerFunction === 'function') {\n scopedContainer.registerFunction(Navigation, () => getNavigation());\n scopedContainer.registerFunction(App, () => getApp());\n scopedContainer.registerFunction(Ipc, () => getIpc());\n }\n\n return scopedContainer as WoodScopedContainer;\n}\n\nasync function resolveController(\n entry: GeneratedAppViewEntry,\n ControllerClass: any,\n contextLabel: string,\n): Promise<unknown> {\n const scopedContainer = createScopedContainer();\n\n if (typeof ControllerClass !== 'function') {\n throw new Error(\n \\`Controller for \\${contextLabel} in view \"\\${entry.key}\" is invalid. Expected a default exported class.\\`,\n );\n }\n\n if (typeof scopedContainer.registerClass === 'function') {\n scopedContainer.registerClass(ControllerClass);\n }\n\n return await scopedContainer.get(ControllerClass);\n}\n\nasync function createViewController(\n entry: GeneratedAppViewEntry,\n): Promise<unknown> {\n if (!entry.controllerClass) {\n return undefined;\n }\n\n return await resolveController(entry, entry.controllerClass, 'page');\n}\n\nasync function createLayoutControllers(\n entry: GeneratedAppViewEntry,\n startIndex = 0,\n): Promise<Array<unknown>> {\n const controllers: unknown[] = [];\n\n for (let i = 0; i < startIndex; i += 1) {\n controllers.push(undefined);\n }\n\n for (let i = startIndex; i < entry.layoutControllerClasses.length; i += 1) {\n const LayoutController = entry.layoutControllerClasses[i];\n if (!LayoutController) {\n controllers.push(undefined);\n continue;\n }\n const controller = await resolveController(\n entry,\n LayoutController,\n \\`layout[\\${i}]\\`,\n );\n controllers.push(controller);\n }\n\n return controllers;\n}\n\nconst DEFAULT_VIEW_KEY = '${escapeSingleQuoted(defaultViewKey)}';\n\ntype WoodWindowBootstrapInfo = {\n ok?: boolean;\n windowId?: string;\n defaultRoute?: string;\n};\n\ntype WoodBootstrapBridgeLike = {\n __window?: {\n current?: () => Promise<WoodWindowBootstrapInfo>;\n };\n};\n\nfunction getWoodBridge(): WoodBootstrapBridgeLike | null {\n const globalObj = globalThis as typeof globalThis & {\n __NOEGO_WOOD_BRIDGE__?: unknown;\n window?: {\n __NOEGO_WOOD_BRIDGE__?: unknown;\n };\n };\n\n const bridge = globalObj.__NOEGO_WOOD_BRIDGE__ ?? globalObj.window?.__NOEGO_WOOD_BRIDGE__;\n if (!bridge || typeof bridge !== 'object') {\n return null;\n }\n\n return bridge as WoodBootstrapBridgeLike;\n}\n\nasync function resolveInitialEntry(): Promise<GeneratedAppViewEntry> {\n if (!DEFAULT_VIEW_KEY) {\n throw new Error('No views available in renderer manifest. Define at least one view in renderer OpenAPI YAML.');\n }\n\n const bridge = getWoodBridge();\n const bootstrapWindow = await bridge?.__window?.current?.();\n const requestedRoute = bootstrapWindow?.defaultRoute;\n\n if (requestedRoute) {\n const routeEntry = getViewManifestEntry(requestedRoute);\n if (routeEntry) {\n return routeEntry;\n }\n }\n\n const entry = getViewManifestEntry(DEFAULT_VIEW_KEY);\n if (!entry) {\n throw new Error(\\`Default view \"\\${DEFAULT_VIEW_KEY}\" is missing from generated view manifest.\\`);\n }\n\n return entry;\n}\n\nexport async function app(target: Element) {\n const entry = await resolveInitialEntry();\n\n getNavigation().replace(entry.key, {}, {});\n const controller = await createViewController(entry);\n const layoutControllers = await createLayoutControllers(entry);\n\n return mount(NavigationShell, {\n target,\n props: {\n manifest: VIEW_MANIFEST,\n initialEntry: entry,\n initialController: controller,\n initialLayoutControllers: layoutControllers,\n createViewControllerFn: createViewController,\n createLayoutControllersFn: createLayoutControllers,\n getViewManifestEntryFn: getViewManifestEntry,\n },\n });\n}\n`;\n}\n"],"mappings":"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","names":["path"]}
|
|
@@ -150,6 +150,15 @@ function generateRendererApp(views, options) {
|
|
|
150
150
|
);
|
|
151
151
|
const layoutControllerPaths = `[${normalizedLayoutControllerRefs.map((controllerRef) => controllerRef ? `'${escapeSingleQuoted(controllerRef)}'` : "undefined").join(", ")}]`;
|
|
152
152
|
const layoutControllerClasses = `[${normalizedLayoutControllerRefs.map((controllerRef) => controllerRef ? controllerIdentifiers.get(controllerRef).identifier : "undefined").join(", ")}]`;
|
|
153
|
+
const layoutPreserve = view.layoutPreserve ?? Array.from(
|
|
154
|
+
{ length: view.layouts.length },
|
|
155
|
+
() => false
|
|
156
|
+
);
|
|
157
|
+
if (layoutPreserve.length !== view.layouts.length) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`Renderer app codegen failed: layout preserve count for view "${key}" does not match layout count.`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
153
162
|
return ` '${escapeSingleQuoted(key)}': {
|
|
154
163
|
key: '${escapeSingleQuoted(key)}',
|
|
155
164
|
windowName: '${escapeSingleQuoted(view.windowName)}',
|
|
@@ -157,6 +166,7 @@ function generateRendererApp(views, options) {
|
|
|
157
166
|
viewPath: '${escapeSingleQuoted(view.viewPath)}',
|
|
158
167
|
layoutPaths: ${JSON.stringify(view.layouts)},
|
|
159
168
|
layoutControllers: ${layoutControllerPaths},
|
|
169
|
+
layoutPreserve: ${JSON.stringify(layoutPreserve)},
|
|
160
170
|
controller: ${controllerPath},
|
|
161
171
|
layoutControllerClasses: ${layoutControllerClasses},
|
|
162
172
|
controllerClass: ${controllerClass},
|
|
@@ -179,6 +189,7 @@ interface GeneratedAppViewEntry {
|
|
|
179
189
|
viewPath: string;
|
|
180
190
|
layoutPaths: string[];
|
|
181
191
|
layoutControllers: Array<string | undefined>;
|
|
192
|
+
layoutPreserve: boolean[];
|
|
182
193
|
controller?: string;
|
|
183
194
|
layoutControllerClasses: Array<any | undefined>;
|
|
184
195
|
controllerClass?: any;
|
|
@@ -261,10 +272,15 @@ async function createViewController(
|
|
|
261
272
|
|
|
262
273
|
async function createLayoutControllers(
|
|
263
274
|
entry: GeneratedAppViewEntry,
|
|
275
|
+
startIndex = 0,
|
|
264
276
|
): Promise<Array<unknown>> {
|
|
265
277
|
const controllers: unknown[] = [];
|
|
266
278
|
|
|
267
|
-
for (let i = 0; i <
|
|
279
|
+
for (let i = 0; i < startIndex; i += 1) {
|
|
280
|
+
controllers.push(undefined);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
for (let i = startIndex; i < entry.layoutControllerClasses.length; i += 1) {
|
|
268
284
|
const LayoutController = entry.layoutControllerClasses[i];
|
|
269
285
|
if (!LayoutController) {
|
|
270
286
|
controllers.push(undefined);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/codegen/renderer_app_generator.ts"],"sourcesContent":["import { existsSync } from 'fs';\nimport path from 'path';\nimport type { ViewDef } from '../types/index.js';\n\nexport interface RendererAppGeneratorOptions {\n /** Absolute path to renderer component root (e.g. /app/ui) */\n componentDir: string;\n /** Absolute output directory where generated file will be written */\n outDir: string;\n /** Optional explicit default view key (e.g. \"main.chat\") */\n entryViewKey?: string;\n}\n\nfunction computeImportPath(fromDir: string, toFile: string): string {\n let rel = path.relative(fromDir, toFile);\n\n if (!rel.startsWith('.')) {\n rel = './' + rel;\n }\n\n return rel.replace(/\\\\/g, '/');\n}\n\nfunction resolveFromComponentDir(componentDir: string, fileRef: string): string {\n if (path.isAbsolute(fileRef)) {\n return fileRef;\n }\n\n const normalizedRef = fileRef.replace(/\\\\/g, '/');\n const componentDirName = path.basename(componentDir).replace(/\\\\/g, '/');\n\n if (normalizedRef.startsWith(componentDirName + '/')) {\n const stripped = normalizedRef.slice(componentDirName.length + 1);\n return path.resolve(componentDir, stripped);\n }\n\n return path.resolve(componentDir, normalizedRef);\n}\n\nfunction viewKey(view: ViewDef): string {\n return `${view.windowName}.${view.pageName}`;\n}\n\nfunction toIdentifier(prefix: string, value: string): string {\n const core = value\n .replace(/[^a-zA-Z0-9]+/g, ' ')\n .trim()\n .split(/\\s+/)\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n .join('');\n\n return `${prefix}${core || 'Component'}`;\n}\n\nfunction escapeSingleQuoted(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\nconst CONTROLLER_FILE_SUFFIXES = [\n '.ts',\n '.js',\n '.controller.ts',\n '.controller.js',\n] as const;\n\nconst CONTROLLER_INDEX_CANDIDATES = [\n 'index.ts',\n 'index.js',\n] as const;\n\nfunction resolveControllerFile(controllerRef: string, componentDir: string): string | null {\n const normalized = controllerRef.trim();\n const basePath = resolveFromComponentDir(componentDir, normalized);\n\n if (existsSync(basePath)) {\n return basePath;\n }\n\n if (path.extname(basePath)) {\n return null;\n }\n\n for (const suffix of CONTROLLER_FILE_SUFFIXES) {\n const candidate = basePath + suffix;\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n for (const indexFile of CONTROLLER_INDEX_CANDIDATES) {\n const candidate = path.resolve(basePath, indexFile);\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\nfunction resolveDefaultViewKey(sortedViews: ViewDef[], entryViewKey?: string): string {\n if (sortedViews.length === 0) return '';\n\n const configuredEntry = entryViewKey?.trim();\n if (!configuredEntry) {\n return viewKey(sortedViews[0]);\n }\n\n const availableKeys = sortedViews.map((view) => viewKey(view));\n if (availableKeys.includes(configuredEntry)) {\n return configuredEntry;\n }\n\n throw new Error(\n `Renderer entry \"${configuredEntry}\" was not found in parsed views. Available view keys: ${availableKeys.join(', ')}`,\n );\n}\n\nexport function generateRendererApp(\n views: ViewDef[],\n options: RendererAppGeneratorOptions,\n): string {\n const sortedViews = [...views].sort((a, b) => viewKey(a).localeCompare(viewKey(b)));\n const defaultViewKey = resolveDefaultViewKey(sortedViews, options.entryViewKey);\n\n const importLines: string[] = [];\n const viewIdentifiers = new Map<string, string>();\n const layoutIdentifiers = new Map<string, string>();\n const controllerIdentifiers = new Map<string, { identifier: string; importPath: string }>();\n const usedNames = new Set<string>();\n\n const allocateName = (prefix: string, filePath: string): string => {\n const base = toIdentifier(prefix, filePath);\n let name = base;\n let suffix = 2;\n while (usedNames.has(name)) {\n name = `${base}${suffix}`;\n suffix += 1;\n }\n usedNames.add(name);\n return name;\n };\n\n const ensureControllerImported = (controllerRef: string, owningViewKey: string): void => {\n if (controllerIdentifiers.has(controllerRef)) return;\n\n const resolvedControllerFile = resolveControllerFile(controllerRef, options.componentDir);\n if (!resolvedControllerFile) {\n throw new Error(\n `Renderer app codegen failed: controller \"${controllerRef}\" for view \"${owningViewKey}\" was not found. ` +\n 'Controller must point to an existing file with a default exported class.',\n );\n }\n\n const identifier = allocateName('PageController', controllerRef);\n const importPath = computeImportPath(options.outDir, resolvedControllerFile);\n controllerIdentifiers.set(controllerRef, { identifier, importPath });\n importLines.push(`import ${identifier} from '${importPath}';`);\n };\n\n for (const view of sortedViews) {\n if (!viewIdentifiers.has(view.viewPath)) {\n const identifier = allocateName('View', view.viewPath);\n viewIdentifiers.set(view.viewPath, identifier);\n const abs = resolveFromComponentDir(options.componentDir, view.viewPath);\n const importPath = computeImportPath(options.outDir, abs);\n importLines.push(`import ${identifier} from '${importPath}';`);\n }\n\n for (const layoutPath of view.layouts) {\n if (layoutIdentifiers.has(layoutPath)) continue;\n const identifier = allocateName('Layout', layoutPath);\n layoutIdentifiers.set(layoutPath, identifier);\n const abs = resolveFromComponentDir(options.componentDir, layoutPath);\n const importPath = computeImportPath(options.outDir, abs);\n importLines.push(`import ${identifier} from '${importPath}';`);\n }\n\n if (view.controller) {\n ensureControllerImported(view.controller, viewKey(view));\n }\n\n for (const layoutController of view.layoutControllers ?? []) {\n if (!layoutController) continue;\n ensureControllerImported(layoutController, viewKey(view));\n }\n }\n\n const manifestEntries = sortedViews.map((view) => {\n const key = viewKey(view);\n const viewIdentifier = viewIdentifiers.get(view.viewPath)!;\n const layoutList = view.layouts.map((layoutPath) => layoutIdentifiers.get(layoutPath)!);\n const controllerPath = view.controller ? `'${escapeSingleQuoted(view.controller)}'` : 'undefined';\n const controllerClass = view.controller\n ? controllerIdentifiers.get(view.controller)!.identifier\n : 'undefined';\n const layoutControllerRefs = view.layoutControllers;\n if (layoutControllerRefs && layoutControllerRefs.length !== view.layouts.length) {\n throw new Error(\n `Renderer app codegen failed: layout controller count for view \"${key}\" does not match layout count.`,\n );\n }\n const normalizedLayoutControllerRefs = layoutControllerRefs ?? Array.from(\n { length: view.layouts.length },\n () => undefined,\n );\n const layoutControllerPaths = `[${normalizedLayoutControllerRefs\n .map((controllerRef) => (controllerRef ? `'${escapeSingleQuoted(controllerRef)}'` : 'undefined'))\n .join(', ')}]`;\n const layoutControllerClasses = `[${normalizedLayoutControllerRefs\n .map((controllerRef) => (controllerRef ? controllerIdentifiers.get(controllerRef)!.identifier : 'undefined'))\n .join(', ')}]`;\n\n return ` '${escapeSingleQuoted(key)}': {\n key: '${escapeSingleQuoted(key)}',\n windowName: '${escapeSingleQuoted(view.windowName)}',\n pageName: '${escapeSingleQuoted(view.pageName)}',\n viewPath: '${escapeSingleQuoted(view.viewPath)}',\n layoutPaths: ${JSON.stringify(view.layouts)},\n layoutControllers: ${layoutControllerPaths},\n controller: ${controllerPath},\n layoutControllerClasses: ${layoutControllerClasses},\n controllerClass: ${controllerClass},\n view: ${viewIdentifier},\n layouts: [${layoutList.join(', ')}],\n },`;\n });\n\n return `// AUTO-GENERATED by @noego/wood -- do not edit\nimport { mount } from 'svelte';\nimport { App, getApp, getContainer } from '@noego/wood/client';\nimport { Navigation, getNavigation } from '@noego/wood/navigation';\nimport { Ipc, getIpc } from '@noego/wood/ipc';\nimport NavigationShell from '@noego/wood/navigation-shell';\n${importLines.join('\\n')}\n\ninterface GeneratedAppViewEntry {\n key: string;\n windowName: string;\n pageName: string;\n viewPath: string;\n layoutPaths: string[];\n layoutControllers: Array<string | undefined>;\n controller?: string;\n layoutControllerClasses: Array<any | undefined>;\n controllerClass?: any;\n view: any;\n layouts: any[];\n}\n\nconst VIEW_MANIFEST: Record<string, GeneratedAppViewEntry> = {\n${manifestEntries.join('\\n')}\n};\n\nfunction getViewManifestEntry(viewKey: string): GeneratedAppViewEntry | null {\n return VIEW_MANIFEST[viewKey] ?? null;\n}\n\ninterface WoodScopedContainer {\n get(token: any): unknown | Promise<unknown>;\n registerClass?(token: any): void;\n registerFunction?(\n token: any,\n resolver: (...args: any[]) => unknown,\n options?: Record<string, unknown>,\n ): void;\n}\n\ninterface WoodContainer extends WoodScopedContainer {\n extend?(): WoodScopedContainer;\n}\n\nfunction createScopedContainer(): WoodScopedContainer {\n const container = getContainer() as WoodContainer;\n if (typeof container.extend !== 'function') {\n throw new Error('Wood client container does not support extend().');\n }\n\n const scopedContainer = container.extend();\n\n if (!scopedContainer || typeof scopedContainer.get !== 'function') {\n throw new Error('Wood client container does not support get().');\n }\n\n if (typeof scopedContainer.registerFunction === 'function') {\n scopedContainer.registerFunction(Navigation, () => getNavigation());\n scopedContainer.registerFunction(App, () => getApp());\n scopedContainer.registerFunction(Ipc, () => getIpc());\n }\n\n return scopedContainer as WoodScopedContainer;\n}\n\nasync function resolveController(\n entry: GeneratedAppViewEntry,\n ControllerClass: any,\n contextLabel: string,\n): Promise<unknown> {\n const scopedContainer = createScopedContainer();\n\n if (typeof ControllerClass !== 'function') {\n throw new Error(\n \\`Controller for \\${contextLabel} in view \"\\${entry.key}\" is invalid. Expected a default exported class.\\`,\n );\n }\n\n if (typeof scopedContainer.registerClass === 'function') {\n scopedContainer.registerClass(ControllerClass);\n }\n\n return await scopedContainer.get(ControllerClass);\n}\n\nasync function createViewController(\n entry: GeneratedAppViewEntry,\n): Promise<unknown> {\n if (!entry.controllerClass) {\n return undefined;\n }\n\n return await resolveController(entry, entry.controllerClass, 'page');\n}\n\nasync function createLayoutControllers(\n entry: GeneratedAppViewEntry,\n): Promise<Array<unknown>> {\n const controllers: unknown[] = [];\n\n for (let i = 0; i < entry.layoutControllerClasses.length; i += 1) {\n const LayoutController = entry.layoutControllerClasses[i];\n if (!LayoutController) {\n controllers.push(undefined);\n continue;\n }\n const controller = await resolveController(\n entry,\n LayoutController,\n \\`layout[\\${i}]\\`,\n );\n controllers.push(controller);\n }\n\n return controllers;\n}\n\nconst DEFAULT_VIEW_KEY = '${escapeSingleQuoted(defaultViewKey)}';\n\ntype WoodWindowBootstrapInfo = {\n ok?: boolean;\n windowId?: string;\n defaultRoute?: string;\n};\n\ntype WoodBootstrapBridgeLike = {\n __window?: {\n current?: () => Promise<WoodWindowBootstrapInfo>;\n };\n};\n\nfunction getWoodBridge(): WoodBootstrapBridgeLike | null {\n const globalObj = globalThis as typeof globalThis & {\n __NOEGO_WOOD_BRIDGE__?: unknown;\n window?: {\n __NOEGO_WOOD_BRIDGE__?: unknown;\n };\n };\n\n const bridge = globalObj.__NOEGO_WOOD_BRIDGE__ ?? globalObj.window?.__NOEGO_WOOD_BRIDGE__;\n if (!bridge || typeof bridge !== 'object') {\n return null;\n }\n\n return bridge as WoodBootstrapBridgeLike;\n}\n\nasync function resolveInitialEntry(): Promise<GeneratedAppViewEntry> {\n if (!DEFAULT_VIEW_KEY) {\n throw new Error('No views available in renderer manifest. Define at least one view in renderer OpenAPI YAML.');\n }\n\n const bridge = getWoodBridge();\n const bootstrapWindow = await bridge?.__window?.current?.();\n const requestedRoute = bootstrapWindow?.defaultRoute;\n\n if (requestedRoute) {\n const routeEntry = getViewManifestEntry(requestedRoute);\n if (routeEntry) {\n return routeEntry;\n }\n }\n\n const entry = getViewManifestEntry(DEFAULT_VIEW_KEY);\n if (!entry) {\n throw new Error(\\`Default view \"\\${DEFAULT_VIEW_KEY}\" is missing from generated view manifest.\\`);\n }\n\n return entry;\n}\n\nexport async function app(target: Element) {\n const entry = await resolveInitialEntry();\n\n getNavigation().replace(entry.key, {}, {});\n const controller = await createViewController(entry);\n const layoutControllers = await createLayoutControllers(entry);\n\n return mount(NavigationShell, {\n target,\n props: {\n manifest: VIEW_MANIFEST,\n initialEntry: entry,\n initialController: controller,\n initialLayoutControllers: layoutControllers,\n createViewControllerFn: createViewController,\n createLayoutControllersFn: createLayoutControllers,\n getViewManifestEntryFn: getViewManifestEntry,\n },\n });\n}\n`;\n}\n"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BA8FA,mBAAmB,cAAc,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2E9D;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/codegen/renderer_app_generator.ts"],"sourcesContent":["import { existsSync } from 'fs';\nimport path from 'path';\nimport type { ViewDef } from '../types/index.js';\n\nexport interface RendererAppGeneratorOptions {\n /** Absolute path to renderer component root (e.g. /app/ui) */\n componentDir: string;\n /** Absolute output directory where generated file will be written */\n outDir: string;\n /** Optional explicit default view key (e.g. \"main.chat\") */\n entryViewKey?: string;\n}\n\nfunction computeImportPath(fromDir: string, toFile: string): string {\n let rel = path.relative(fromDir, toFile);\n\n if (!rel.startsWith('.')) {\n rel = './' + rel;\n }\n\n return rel.replace(/\\\\/g, '/');\n}\n\nfunction resolveFromComponentDir(componentDir: string, fileRef: string): string {\n if (path.isAbsolute(fileRef)) {\n return fileRef;\n }\n\n const normalizedRef = fileRef.replace(/\\\\/g, '/');\n const componentDirName = path.basename(componentDir).replace(/\\\\/g, '/');\n\n if (normalizedRef.startsWith(componentDirName + '/')) {\n const stripped = normalizedRef.slice(componentDirName.length + 1);\n return path.resolve(componentDir, stripped);\n }\n\n return path.resolve(componentDir, normalizedRef);\n}\n\nfunction viewKey(view: ViewDef): string {\n return `${view.windowName}.${view.pageName}`;\n}\n\nfunction toIdentifier(prefix: string, value: string): string {\n const core = value\n .replace(/[^a-zA-Z0-9]+/g, ' ')\n .trim()\n .split(/\\s+/)\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n .join('');\n\n return `${prefix}${core || 'Component'}`;\n}\n\nfunction escapeSingleQuoted(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\nconst CONTROLLER_FILE_SUFFIXES = [\n '.ts',\n '.js',\n '.controller.ts',\n '.controller.js',\n] as const;\n\nconst CONTROLLER_INDEX_CANDIDATES = [\n 'index.ts',\n 'index.js',\n] as const;\n\nfunction resolveControllerFile(controllerRef: string, componentDir: string): string | null {\n const normalized = controllerRef.trim();\n const basePath = resolveFromComponentDir(componentDir, normalized);\n\n if (existsSync(basePath)) {\n return basePath;\n }\n\n if (path.extname(basePath)) {\n return null;\n }\n\n for (const suffix of CONTROLLER_FILE_SUFFIXES) {\n const candidate = basePath + suffix;\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n for (const indexFile of CONTROLLER_INDEX_CANDIDATES) {\n const candidate = path.resolve(basePath, indexFile);\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\nfunction resolveDefaultViewKey(sortedViews: ViewDef[], entryViewKey?: string): string {\n if (sortedViews.length === 0) return '';\n\n const configuredEntry = entryViewKey?.trim();\n if (!configuredEntry) {\n return viewKey(sortedViews[0]);\n }\n\n const availableKeys = sortedViews.map((view) => viewKey(view));\n if (availableKeys.includes(configuredEntry)) {\n return configuredEntry;\n }\n\n throw new Error(\n `Renderer entry \"${configuredEntry}\" was not found in parsed views. Available view keys: ${availableKeys.join(', ')}`,\n );\n}\n\nexport function generateRendererApp(\n views: ViewDef[],\n options: RendererAppGeneratorOptions,\n): string {\n const sortedViews = [...views].sort((a, b) => viewKey(a).localeCompare(viewKey(b)));\n const defaultViewKey = resolveDefaultViewKey(sortedViews, options.entryViewKey);\n\n const importLines: string[] = [];\n const viewIdentifiers = new Map<string, string>();\n const layoutIdentifiers = new Map<string, string>();\n const controllerIdentifiers = new Map<string, { identifier: string; importPath: string }>();\n const usedNames = new Set<string>();\n\n const allocateName = (prefix: string, filePath: string): string => {\n const base = toIdentifier(prefix, filePath);\n let name = base;\n let suffix = 2;\n while (usedNames.has(name)) {\n name = `${base}${suffix}`;\n suffix += 1;\n }\n usedNames.add(name);\n return name;\n };\n\n const ensureControllerImported = (controllerRef: string, owningViewKey: string): void => {\n if (controllerIdentifiers.has(controllerRef)) return;\n\n const resolvedControllerFile = resolveControllerFile(controllerRef, options.componentDir);\n if (!resolvedControllerFile) {\n throw new Error(\n `Renderer app codegen failed: controller \"${controllerRef}\" for view \"${owningViewKey}\" was not found. ` +\n 'Controller must point to an existing file with a default exported class.',\n );\n }\n\n const identifier = allocateName('PageController', controllerRef);\n const importPath = computeImportPath(options.outDir, resolvedControllerFile);\n controllerIdentifiers.set(controllerRef, { identifier, importPath });\n importLines.push(`import ${identifier} from '${importPath}';`);\n };\n\n for (const view of sortedViews) {\n if (!viewIdentifiers.has(view.viewPath)) {\n const identifier = allocateName('View', view.viewPath);\n viewIdentifiers.set(view.viewPath, identifier);\n const abs = resolveFromComponentDir(options.componentDir, view.viewPath);\n const importPath = computeImportPath(options.outDir, abs);\n importLines.push(`import ${identifier} from '${importPath}';`);\n }\n\n for (const layoutPath of view.layouts) {\n if (layoutIdentifiers.has(layoutPath)) continue;\n const identifier = allocateName('Layout', layoutPath);\n layoutIdentifiers.set(layoutPath, identifier);\n const abs = resolveFromComponentDir(options.componentDir, layoutPath);\n const importPath = computeImportPath(options.outDir, abs);\n importLines.push(`import ${identifier} from '${importPath}';`);\n }\n\n if (view.controller) {\n ensureControllerImported(view.controller, viewKey(view));\n }\n\n for (const layoutController of view.layoutControllers ?? []) {\n if (!layoutController) continue;\n ensureControllerImported(layoutController, viewKey(view));\n }\n }\n\n const manifestEntries = sortedViews.map((view) => {\n const key = viewKey(view);\n const viewIdentifier = viewIdentifiers.get(view.viewPath)!;\n const layoutList = view.layouts.map((layoutPath) => layoutIdentifiers.get(layoutPath)!);\n const controllerPath = view.controller ? `'${escapeSingleQuoted(view.controller)}'` : 'undefined';\n const controllerClass = view.controller\n ? controllerIdentifiers.get(view.controller)!.identifier\n : 'undefined';\n const layoutControllerRefs = view.layoutControllers;\n if (layoutControllerRefs && layoutControllerRefs.length !== view.layouts.length) {\n throw new Error(\n `Renderer app codegen failed: layout controller count for view \"${key}\" does not match layout count.`,\n );\n }\n const normalizedLayoutControllerRefs = layoutControllerRefs ?? Array.from(\n { length: view.layouts.length },\n () => undefined,\n );\n const layoutControllerPaths = `[${normalizedLayoutControllerRefs\n .map((controllerRef) => (controllerRef ? `'${escapeSingleQuoted(controllerRef)}'` : 'undefined'))\n .join(', ')}]`;\n const layoutControllerClasses = `[${normalizedLayoutControllerRefs\n .map((controllerRef) => (controllerRef ? controllerIdentifiers.get(controllerRef)!.identifier : 'undefined'))\n .join(', ')}]`;\n const layoutPreserve = view.layoutPreserve ?? Array.from(\n { length: view.layouts.length },\n () => false,\n );\n if (layoutPreserve.length !== view.layouts.length) {\n throw new Error(\n `Renderer app codegen failed: layout preserve count for view \"${key}\" does not match layout count.`,\n );\n }\n\n return ` '${escapeSingleQuoted(key)}': {\n key: '${escapeSingleQuoted(key)}',\n windowName: '${escapeSingleQuoted(view.windowName)}',\n pageName: '${escapeSingleQuoted(view.pageName)}',\n viewPath: '${escapeSingleQuoted(view.viewPath)}',\n layoutPaths: ${JSON.stringify(view.layouts)},\n layoutControllers: ${layoutControllerPaths},\n layoutPreserve: ${JSON.stringify(layoutPreserve)},\n controller: ${controllerPath},\n layoutControllerClasses: ${layoutControllerClasses},\n controllerClass: ${controllerClass},\n view: ${viewIdentifier},\n layouts: [${layoutList.join(', ')}],\n },`;\n });\n\n return `// AUTO-GENERATED by @noego/wood -- do not edit\nimport { mount } from 'svelte';\nimport { App, getApp, getContainer } from '@noego/wood/client';\nimport { Navigation, getNavigation } from '@noego/wood/navigation';\nimport { Ipc, getIpc } from '@noego/wood/ipc';\nimport NavigationShell from '@noego/wood/navigation-shell';\n${importLines.join('\\n')}\n\ninterface GeneratedAppViewEntry {\n key: string;\n windowName: string;\n pageName: string;\n viewPath: string;\n layoutPaths: string[];\n layoutControllers: Array<string | undefined>;\n layoutPreserve: boolean[];\n controller?: string;\n layoutControllerClasses: Array<any | undefined>;\n controllerClass?: any;\n view: any;\n layouts: any[];\n}\n\nconst VIEW_MANIFEST: Record<string, GeneratedAppViewEntry> = {\n${manifestEntries.join('\\n')}\n};\n\nfunction getViewManifestEntry(viewKey: string): GeneratedAppViewEntry | null {\n return VIEW_MANIFEST[viewKey] ?? null;\n}\n\ninterface WoodScopedContainer {\n get(token: any): unknown | Promise<unknown>;\n registerClass?(token: any): void;\n registerFunction?(\n token: any,\n resolver: (...args: any[]) => unknown,\n options?: Record<string, unknown>,\n ): void;\n}\n\ninterface WoodContainer extends WoodScopedContainer {\n extend?(): WoodScopedContainer;\n}\n\nfunction createScopedContainer(): WoodScopedContainer {\n const container = getContainer() as WoodContainer;\n if (typeof container.extend !== 'function') {\n throw new Error('Wood client container does not support extend().');\n }\n\n const scopedContainer = container.extend();\n\n if (!scopedContainer || typeof scopedContainer.get !== 'function') {\n throw new Error('Wood client container does not support get().');\n }\n\n if (typeof scopedContainer.registerFunction === 'function') {\n scopedContainer.registerFunction(Navigation, () => getNavigation());\n scopedContainer.registerFunction(App, () => getApp());\n scopedContainer.registerFunction(Ipc, () => getIpc());\n }\n\n return scopedContainer as WoodScopedContainer;\n}\n\nasync function resolveController(\n entry: GeneratedAppViewEntry,\n ControllerClass: any,\n contextLabel: string,\n): Promise<unknown> {\n const scopedContainer = createScopedContainer();\n\n if (typeof ControllerClass !== 'function') {\n throw new Error(\n \\`Controller for \\${contextLabel} in view \"\\${entry.key}\" is invalid. Expected a default exported class.\\`,\n );\n }\n\n if (typeof scopedContainer.registerClass === 'function') {\n scopedContainer.registerClass(ControllerClass);\n }\n\n return await scopedContainer.get(ControllerClass);\n}\n\nasync function createViewController(\n entry: GeneratedAppViewEntry,\n): Promise<unknown> {\n if (!entry.controllerClass) {\n return undefined;\n }\n\n return await resolveController(entry, entry.controllerClass, 'page');\n}\n\nasync function createLayoutControllers(\n entry: GeneratedAppViewEntry,\n startIndex = 0,\n): Promise<Array<unknown>> {\n const controllers: unknown[] = [];\n\n for (let i = 0; i < startIndex; i += 1) {\n controllers.push(undefined);\n }\n\n for (let i = startIndex; i < entry.layoutControllerClasses.length; i += 1) {\n const LayoutController = entry.layoutControllerClasses[i];\n if (!LayoutController) {\n controllers.push(undefined);\n continue;\n }\n const controller = await resolveController(\n entry,\n LayoutController,\n \\`layout[\\${i}]\\`,\n );\n controllers.push(controller);\n }\n\n return controllers;\n}\n\nconst DEFAULT_VIEW_KEY = '${escapeSingleQuoted(defaultViewKey)}';\n\ntype WoodWindowBootstrapInfo = {\n ok?: boolean;\n windowId?: string;\n defaultRoute?: string;\n};\n\ntype WoodBootstrapBridgeLike = {\n __window?: {\n current?: () => Promise<WoodWindowBootstrapInfo>;\n };\n};\n\nfunction getWoodBridge(): WoodBootstrapBridgeLike | null {\n const globalObj = globalThis as typeof globalThis & {\n __NOEGO_WOOD_BRIDGE__?: unknown;\n window?: {\n __NOEGO_WOOD_BRIDGE__?: unknown;\n };\n };\n\n const bridge = globalObj.__NOEGO_WOOD_BRIDGE__ ?? globalObj.window?.__NOEGO_WOOD_BRIDGE__;\n if (!bridge || typeof bridge !== 'object') {\n return null;\n }\n\n return bridge as WoodBootstrapBridgeLike;\n}\n\nasync function resolveInitialEntry(): Promise<GeneratedAppViewEntry> {\n if (!DEFAULT_VIEW_KEY) {\n throw new Error('No views available in renderer manifest. Define at least one view in renderer OpenAPI YAML.');\n }\n\n const bridge = getWoodBridge();\n const bootstrapWindow = await bridge?.__window?.current?.();\n const requestedRoute = bootstrapWindow?.defaultRoute;\n\n if (requestedRoute) {\n const routeEntry = getViewManifestEntry(requestedRoute);\n if (routeEntry) {\n return routeEntry;\n }\n }\n\n const entry = getViewManifestEntry(DEFAULT_VIEW_KEY);\n if (!entry) {\n throw new Error(\\`Default view \"\\${DEFAULT_VIEW_KEY}\" is missing from generated view manifest.\\`);\n }\n\n return entry;\n}\n\nexport async function app(target: Element) {\n const entry = await resolveInitialEntry();\n\n getNavigation().replace(entry.key, {}, {});\n const controller = await createViewController(entry);\n const layoutControllers = await createLayoutControllers(entry);\n\n return mount(NavigationShell, {\n target,\n props: {\n manifest: VIEW_MANIFEST,\n initialEntry: entry,\n initialController: controller,\n initialLayoutControllers: layoutControllers,\n createViewControllerFn: createViewController,\n createLayoutControllersFn: createLayoutControllers,\n getViewManifestEntryFn: getViewManifestEntry,\n },\n });\n}\n`;\n}\n"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAmGA,mBAAmB,cAAc,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2E9D;","names":[]}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// @noego/wood — Declarative Electron desktop apps using the noego ecosystem\n\n// Types\nexport type {\n WoodConfig,\n WindowDef,\n DevConfig,\n ElectronBuilderConfig,\n OperationDef,\n RawOperationsDocument,\n RawModuleDef,\n RawOperationEntry,\n RawModuleOperationEntry,\n ViewDef,\n RawViewsDocument,\n RawViewEntry,\n ParameterDef,\n IpcContext,\n WoodMiddlewareContext,\n WoodMiddlewareFn,\n RequestData,\n ControllerArgs,\n LoaderResult,\n BridgeMessage,\n BridgeRequest,\n BridgeResponse,\n BridgeReady,\n BridgePush,\n BridgeElectronApi,\n SerializedError,\n ContextMenuContext,\n ContextMenuItem,\n ContextMenuEvent,\n} from './types';\n\n// Errors\nexport { WoodAuthError, WoodValidationError, BackendRestartingError } from './types/index.cjs';\n\n// Config\nexport { parseConfig } from './config/index.cjs';\n\n// Parsers\nexport { parseOperations, parseOperationsFile } from './parser/index.cjs';\nexport { parseViews, parseViewsFile } from './parser/index.cjs';\n\n// Router\nexport { WoodRouter } from './router/index.cjs';\n\n// Validation\nexport { SchemaValidator } from './validation/index.cjs';\n\n// Middleware\nexport { MiddlewareResolver, buildMiddlewareContext, executeMiddleware } from './middleware/index.cjs';\n\n// Controller\nexport { ControllerResolver, buildControllerArgs, disposeControllerLifecycle } from './controller/index.cjs';\nexport type { ControllerLifecycle } from './controller/index.cjs';\n\n// Codegen\nexport { generatePreload } from './codegen/index.cjs';\nexport { generateTypes } from './codegen/index.cjs';\nexport { generateTestMock } from './codegen/index.cjs';\nexport { generateControllerRegistration } from './codegen/index.cjs';\nexport type { ControllerRegistrationOptions } from './codegen/index.cjs';\nexport { generateRuntime } from './codegen/index.cjs';\nexport type { RuntimeGeneratorOptions } from './codegen/index.cjs';\nexport { generateRendererViewManifest } from './codegen/index.cjs';\nexport type { RendererViewManifestGeneratorOptions } from './codegen/index.cjs';\nexport { generateRendererControllerRegistration } from './codegen/index.cjs';\nexport type { RendererControllerRegistrationOptions } from './codegen/index.cjs';\nexport { generateRendererApp } from './codegen/index.cjs';\nexport type { RendererAppGeneratorOptions } from './codegen/index.cjs';\n\n// Window\nexport { WindowManager, WindowStateStore } from './window/index.cjs';\nexport type { ScreenLike, WindowBounds } from './window/index.cjs';\n\n// Loader\nexport { LoaderRunner } from './loader/index.cjs';\n\n// Bridge\nexport { BackendBridge, startBackendLoop, pushEvent } from './bridge/index.cjs';\n\n// Dev\nexport {\n WoodDevServer,\n BackendWatcher,\n YamlWatcher,\n DEFAULT_WOOD_REMOTE_DEBUGGING_PORT,\n WOOD_DEV_DIRECTORY,\n WOOD_DEV_METADATA_BASENAME,\n resolveWoodRemoteDebuggingPort,\n resolveWoodDevDirectory,\n resolveWoodDevMetadataPath,\n writeWoodDevMetadata,\n readWoodDevMetadata,\n removeWoodDevMetadata,\n} from './dev/index.js';\nexport type { WoodDevMetadata } from './dev/index.js';\n\n// Runtime\nexport {\n getContainer,\n clearContainerRegistryForTests,\n getApplicationRoot,\n setApplicationRoot,\n clearApplicationRootForTests,\n runtime,\n} from './runtime/index.js';\nexport type {\n GetContainerOptions,\n RuntimeOptions,\n RuntimeResult,\n RegisterRuntimeRouter,\n} from './runtime';\n\n// Navigation\nexport { Navigation, getNavigation, go, goto, goback } from './navigation/index.cjs';\nexport type { NavigationEntry } from './navigation/index.cjs';\n\n// Isomorphic IPC API\nexport { Ipc, getIpc } from './ipc/index.cjs';\nexport type { IpcPushOptions } from './ipc/index.cjs';\n\n// Tracing\nexport {\n FrameworkTracer,\n MainTracer,\n RendererTracer,\n TestTracer,\n TraceProvider,\n TraceProviderConfiguration,\n TraceCapture,\n clearTraceHubForTests,\n createTraceCapture,\n getTraceEvents$,\n setRendererTraceEnabled,\n setRendererTraceTransport,\n} from './tracing/index.js';\nexport type {\n TraceCaptureOptions,\n TraceDispatchResult,\n TraceEvent,\n TraceInput,\n TraceLevel,\n TraceProcess,\n TraceProviderMode,\n TraceRuntime,\n TraceWaitOptions,\n} from './tracing/index.js';\n\n// Testing — available via '@noego/wood/testing' subpath export.\n// Not re-exported here to avoid pulling vitest into production builds.\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoCA,mBAA2E;AAG3E,oBAA4B;AAG5B,oBAAqD;AACrD,IAAAA,iBAA2C;AAG3C,oBAA2B;AAG3B,wBAAgC;AAGhC,wBAA8E;AAG9E,wBAAoF;AAIpF,qBAAgC;AAChC,IAAAC,kBAA8B;AAC9B,IAAAA,kBAAiC;AACjC,IAAAA,kBAA+C;AAE/C,IAAAA,kBAAgC;AAEhC,IAAAA,kBAA6C;AAE7C,IAAAA,kBAAuD;AAEvD,IAAAA,kBAAoC;AAIpC,oBAAgD;AAIhD,oBAA6B;AAG7B,oBAA2D;AAG3D,iBAaO;AAIP,qBAOO;AASP,wBAA4D;AAI5D,iBAA4B;AAI5B,qBAaO;","names":["import_parser","import_codegen"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// @noego/wood — Declarative Electron desktop apps using the noego ecosystem\n\n// Types\nexport type {\n WoodConfig,\n WindowDef,\n DevConfig,\n ElectronBuilderConfig,\n OperationDef,\n RawOperationsDocument,\n RawModuleDef,\n RawOperationEntry,\n RawModuleOperationEntry,\n ViewDef,\n RawViewsDocument,\n RawViewEntry,\n ParameterDef,\n IpcContext,\n WoodMiddlewareContext,\n WoodMiddlewareFn,\n RequestData,\n ControllerArgs,\n LoaderResult,\n BridgeMessage,\n BridgeRequest,\n BridgeResponse,\n BridgeReady,\n BridgePush,\n BridgeElectronApi,\n SerializedError,\n ContextMenuContext,\n ContextMenuItem,\n ContextMenuEvent,\n} from './types';\n\n// Errors\nexport { WoodAuthError, WoodValidationError, BackendRestartingError } from './types/index.cjs';\n\n// Config\nexport { parseConfig } from './config/index.cjs';\n\n// Parsers\nexport { parseOperations, parseOperationsFile } from './parser/index.cjs';\nexport { parseViews, parseViewsFile } from './parser/index.cjs';\n\n// Router\nexport { WoodRouter } from './router/index.cjs';\n\n// Validation\nexport { SchemaValidator } from './validation/index.cjs';\n\n// Middleware\nexport { MiddlewareResolver, buildMiddlewareContext, executeMiddleware } from './middleware/index.cjs';\n\n// Controller\nexport { ControllerResolver, buildControllerArgs, disposeControllerLifecycle } from './controller/index.cjs';\nexport type { ControllerLifecycle } from './controller/index.cjs';\n\n// Codegen\nexport { generatePreload } from './codegen/index.cjs';\nexport { generateTypes } from './codegen/index.cjs';\nexport { generateTestMock } from './codegen/index.cjs';\nexport { generateControllerRegistration } from './codegen/index.cjs';\nexport type { ControllerRegistrationOptions } from './codegen/index.cjs';\nexport { generateRuntime } from './codegen/index.cjs';\nexport type { RuntimeGeneratorOptions } from './codegen/index.cjs';\nexport { generateRendererViewManifest } from './codegen/index.cjs';\nexport type { RendererViewManifestGeneratorOptions } from './codegen/index.cjs';\nexport { generateRendererControllerRegistration } from './codegen/index.cjs';\nexport type { RendererControllerRegistrationOptions } from './codegen/index.cjs';\nexport { generateRendererApp } from './codegen/index.cjs';\nexport type { RendererAppGeneratorOptions } from './codegen/index.cjs';\n\n// Window\nexport { WindowManager, WindowStateStore } from './window/index.cjs';\nexport type { ScreenLike, WindowBounds } from './window/index.cjs';\n\n// Loader\nexport { LoaderRunner } from './loader/index.cjs';\n\n// Bridge\nexport { BackendBridge, startBackendLoop, pushEvent } from './bridge/index.cjs';\n\n// Dev\nexport {\n WoodDevServer,\n BackendWatcher,\n YamlWatcher,\n DEFAULT_WOOD_REMOTE_DEBUGGING_PORT,\n WOOD_DEV_DIRECTORY,\n WOOD_DEV_METADATA_BASENAME,\n resolveWoodRemoteDebuggingPort,\n resolveWoodDevDirectory,\n resolveWoodDevMetadataPath,\n writeWoodDevMetadata,\n readWoodDevMetadata,\n removeWoodDevMetadata,\n} from './dev/index.js';\nexport type { WoodDevMetadata } from './dev/index.js';\n\n// Runtime\nexport {\n getContainer,\n clearContainerRegistryForTests,\n getApplicationRoot,\n setApplicationRoot,\n clearApplicationRootForTests,\n runtime,\n} from './runtime/index.js';\nexport type {\n GetContainerOptions,\n RuntimeOptions,\n RuntimeResult,\n RegisterRuntimeRouter,\n} from './runtime';\n\n// Navigation\nexport { Navigation, getNavigation, go, goto, goback } from './navigation/index.cjs';\nexport type { NavigationEntry, NavigationOptions } from './navigation/index.cjs';\n\n// Isomorphic IPC API\nexport { Ipc, getIpc } from './ipc/index.cjs';\nexport type { IpcPushOptions } from './ipc/index.cjs';\n\n// Tracing\nexport {\n FrameworkTracer,\n MainTracer,\n RendererTracer,\n TestTracer,\n TraceProvider,\n TraceProviderConfiguration,\n TraceCapture,\n clearTraceHubForTests,\n createTraceCapture,\n getTraceEvents$,\n setRendererTraceEnabled,\n setRendererTraceTransport,\n} from './tracing/index.js';\nexport type {\n TraceCaptureOptions,\n TraceDispatchResult,\n TraceEvent,\n TraceInput,\n TraceLevel,\n TraceProcess,\n TraceProviderMode,\n TraceRuntime,\n TraceWaitOptions,\n} from './tracing/index.js';\n\n// Testing — available via '@noego/wood/testing' subpath export.\n// Not re-exported here to avoid pulling vitest into production builds.\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoCA,mBAA2E;AAG3E,oBAA4B;AAG5B,oBAAqD;AACrD,IAAAA,iBAA2C;AAG3C,oBAA2B;AAG3B,wBAAgC;AAGhC,wBAA8E;AAG9E,wBAAoF;AAIpF,qBAAgC;AAChC,IAAAC,kBAA8B;AAC9B,IAAAA,kBAAiC;AACjC,IAAAA,kBAA+C;AAE/C,IAAAA,kBAAgC;AAEhC,IAAAA,kBAA6C;AAE7C,IAAAA,kBAAuD;AAEvD,IAAAA,kBAAoC;AAIpC,oBAAgD;AAIhD,oBAA6B;AAG7B,oBAA2D;AAG3D,iBAaO;AAIP,qBAOO;AASP,wBAA4D;AAI5D,iBAA4B;AAI5B,qBAaO;","names":["import_parser","import_codegen"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -35,7 +35,7 @@ export { clearApplicationRootForTests, getApplicationRoot, setApplicationRoot }
|
|
|
35
35
|
export { RegisterRuntimeRouter, RuntimeOptions, RuntimeResult, runtime } from './runtime/runtime.cjs';
|
|
36
36
|
export { TraceCapture, TraceCaptureOptions, TraceDispatchResult, TraceEvent, TraceInput, TraceLevel, TraceProcess, TraceWaitOptions, clearTraceHubForTests, createTraceCapture, getTraceEvents$, setRendererTraceEnabled, setRendererTraceTransport } from './tracing/trace_hub.cjs';
|
|
37
37
|
export { FrameworkTracer, MainTracer, RendererTracer, TestTracer, TraceProvider, TraceProviderConfiguration, TraceProviderMode, TraceRuntime } from './tracing/trace_provider.cjs';
|
|
38
|
-
export { Navigation, NavigationEntry, getNavigation, go, goback, goto } from './navigation/index.cjs';
|
|
38
|
+
export { Navigation, NavigationEntry, NavigationOptions, getNavigation, go, goback, goto } from './navigation/index.cjs';
|
|
39
39
|
export { Ipc, getIpc } from './ipc/index.cjs';
|
|
40
40
|
export { IpcPushOptions } from './ipc/shared.cjs';
|
|
41
41
|
import 'rxjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ export { clearApplicationRootForTests, getApplicationRoot, setApplicationRoot }
|
|
|
35
35
|
export { RegisterRuntimeRouter, RuntimeOptions, RuntimeResult, runtime } from './runtime/runtime.js';
|
|
36
36
|
export { TraceCapture, TraceCaptureOptions, TraceDispatchResult, TraceEvent, TraceInput, TraceLevel, TraceProcess, TraceWaitOptions, clearTraceHubForTests, createTraceCapture, getTraceEvents$, setRendererTraceEnabled, setRendererTraceTransport } from './tracing/trace_hub.js';
|
|
37
37
|
export { FrameworkTracer, MainTracer, RendererTracer, TestTracer, TraceProvider, TraceProviderConfiguration, TraceProviderMode, TraceRuntime } from './tracing/trace_provider.js';
|
|
38
|
-
export { Navigation, NavigationEntry, getNavigation, go, goback, goto } from './navigation/index.js';
|
|
38
|
+
export { Navigation, NavigationEntry, NavigationOptions, getNavigation, go, goback, goto } from './navigation/index.js';
|
|
39
39
|
export { Ipc, getIpc } from './ipc/index.js';
|
|
40
40
|
export { IpcPushOptions } from './ipc/shared.js';
|
|
41
41
|
import 'rxjs';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// @noego/wood — Declarative Electron desktop apps using the noego ecosystem\n\n// Types\nexport type {\n WoodConfig,\n WindowDef,\n DevConfig,\n ElectronBuilderConfig,\n OperationDef,\n RawOperationsDocument,\n RawModuleDef,\n RawOperationEntry,\n RawModuleOperationEntry,\n ViewDef,\n RawViewsDocument,\n RawViewEntry,\n ParameterDef,\n IpcContext,\n WoodMiddlewareContext,\n WoodMiddlewareFn,\n RequestData,\n ControllerArgs,\n LoaderResult,\n BridgeMessage,\n BridgeRequest,\n BridgeResponse,\n BridgeReady,\n BridgePush,\n BridgeElectronApi,\n SerializedError,\n ContextMenuContext,\n ContextMenuItem,\n ContextMenuEvent,\n} from './types';\n\n// Errors\nexport { WoodAuthError, WoodValidationError, BackendRestartingError } from './types/index.js';\n\n// Config\nexport { parseConfig } from './config/index.js';\n\n// Parsers\nexport { parseOperations, parseOperationsFile } from './parser/index.js';\nexport { parseViews, parseViewsFile } from './parser/index.js';\n\n// Router\nexport { WoodRouter } from './router/index.js';\n\n// Validation\nexport { SchemaValidator } from './validation/index.js';\n\n// Middleware\nexport { MiddlewareResolver, buildMiddlewareContext, executeMiddleware } from './middleware/index.js';\n\n// Controller\nexport { ControllerResolver, buildControllerArgs, disposeControllerLifecycle } from './controller/index.js';\nexport type { ControllerLifecycle } from './controller/index.js';\n\n// Codegen\nexport { generatePreload } from './codegen/index.js';\nexport { generateTypes } from './codegen/index.js';\nexport { generateTestMock } from './codegen/index.js';\nexport { generateControllerRegistration } from './codegen/index.js';\nexport type { ControllerRegistrationOptions } from './codegen/index.js';\nexport { generateRuntime } from './codegen/index.js';\nexport type { RuntimeGeneratorOptions } from './codegen/index.js';\nexport { generateRendererViewManifest } from './codegen/index.js';\nexport type { RendererViewManifestGeneratorOptions } from './codegen/index.js';\nexport { generateRendererControllerRegistration } from './codegen/index.js';\nexport type { RendererControllerRegistrationOptions } from './codegen/index.js';\nexport { generateRendererApp } from './codegen/index.js';\nexport type { RendererAppGeneratorOptions } from './codegen/index.js';\n\n// Window\nexport { WindowManager, WindowStateStore } from './window/index.js';\nexport type { ScreenLike, WindowBounds } from './window/index.js';\n\n// Loader\nexport { LoaderRunner } from './loader/index.js';\n\n// Bridge\nexport { BackendBridge, startBackendLoop, pushEvent } from './bridge/index.js';\n\n// Dev\nexport {\n WoodDevServer,\n BackendWatcher,\n YamlWatcher,\n DEFAULT_WOOD_REMOTE_DEBUGGING_PORT,\n WOOD_DEV_DIRECTORY,\n WOOD_DEV_METADATA_BASENAME,\n resolveWoodRemoteDebuggingPort,\n resolveWoodDevDirectory,\n resolveWoodDevMetadataPath,\n writeWoodDevMetadata,\n readWoodDevMetadata,\n removeWoodDevMetadata,\n} from './dev/index.js';\nexport type { WoodDevMetadata } from './dev/index.js';\n\n// Runtime\nexport {\n getContainer,\n clearContainerRegistryForTests,\n getApplicationRoot,\n setApplicationRoot,\n clearApplicationRootForTests,\n runtime,\n} from './runtime/index.js';\nexport type {\n GetContainerOptions,\n RuntimeOptions,\n RuntimeResult,\n RegisterRuntimeRouter,\n} from './runtime';\n\n// Navigation\nexport { Navigation, getNavigation, go, goto, goback } from './navigation/index.js';\nexport type { NavigationEntry } from './navigation/index.js';\n\n// Isomorphic IPC API\nexport { Ipc, getIpc } from './ipc/index.js';\nexport type { IpcPushOptions } from './ipc/index.js';\n\n// Tracing\nexport {\n FrameworkTracer,\n MainTracer,\n RendererTracer,\n TestTracer,\n TraceProvider,\n TraceProviderConfiguration,\n TraceCapture,\n clearTraceHubForTests,\n createTraceCapture,\n getTraceEvents$,\n setRendererTraceEnabled,\n setRendererTraceTransport,\n} from './tracing/index.js';\nexport type {\n TraceCaptureOptions,\n TraceDispatchResult,\n TraceEvent,\n TraceInput,\n TraceLevel,\n TraceProcess,\n TraceProviderMode,\n TraceRuntime,\n TraceWaitOptions,\n} from './tracing/index.js';\n\n// Testing — available via '@noego/wood/testing' subpath export.\n// Not re-exported here to avoid pulling vitest into production builds.\n"],"mappings":"AAoCA,SAAS,eAAe,qBAAqB,8BAA8B;AAG3E,SAAS,mBAAmB;AAG5B,SAAS,iBAAiB,2BAA2B;AACrD,SAAS,YAAY,sBAAsB;AAG3C,SAAS,kBAAkB;AAG3B,SAAS,uBAAuB;AAGhC,SAAS,oBAAoB,wBAAwB,yBAAyB;AAG9E,SAAS,oBAAoB,qBAAqB,kCAAkC;AAIpF,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,wBAAwB;AACjC,SAAS,sCAAsC;AAE/C,SAAS,uBAAuB;AAEhC,SAAS,oCAAoC;AAE7C,SAAS,8CAA8C;AAEvD,SAAS,2BAA2B;AAIpC,SAAS,eAAe,wBAAwB;AAIhD,SAAS,oBAAoB;AAG7B,SAAS,eAAe,kBAAkB,iBAAiB;AAG3D;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AASP,SAAS,YAAY,eAAe,IAAI,MAAM,cAAc;AAI5D,SAAS,KAAK,cAAc;AAI5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// @noego/wood — Declarative Electron desktop apps using the noego ecosystem\n\n// Types\nexport type {\n WoodConfig,\n WindowDef,\n DevConfig,\n ElectronBuilderConfig,\n OperationDef,\n RawOperationsDocument,\n RawModuleDef,\n RawOperationEntry,\n RawModuleOperationEntry,\n ViewDef,\n RawViewsDocument,\n RawViewEntry,\n ParameterDef,\n IpcContext,\n WoodMiddlewareContext,\n WoodMiddlewareFn,\n RequestData,\n ControllerArgs,\n LoaderResult,\n BridgeMessage,\n BridgeRequest,\n BridgeResponse,\n BridgeReady,\n BridgePush,\n BridgeElectronApi,\n SerializedError,\n ContextMenuContext,\n ContextMenuItem,\n ContextMenuEvent,\n} from './types';\n\n// Errors\nexport { WoodAuthError, WoodValidationError, BackendRestartingError } from './types/index.js';\n\n// Config\nexport { parseConfig } from './config/index.js';\n\n// Parsers\nexport { parseOperations, parseOperationsFile } from './parser/index.js';\nexport { parseViews, parseViewsFile } from './parser/index.js';\n\n// Router\nexport { WoodRouter } from './router/index.js';\n\n// Validation\nexport { SchemaValidator } from './validation/index.js';\n\n// Middleware\nexport { MiddlewareResolver, buildMiddlewareContext, executeMiddleware } from './middleware/index.js';\n\n// Controller\nexport { ControllerResolver, buildControllerArgs, disposeControllerLifecycle } from './controller/index.js';\nexport type { ControllerLifecycle } from './controller/index.js';\n\n// Codegen\nexport { generatePreload } from './codegen/index.js';\nexport { generateTypes } from './codegen/index.js';\nexport { generateTestMock } from './codegen/index.js';\nexport { generateControllerRegistration } from './codegen/index.js';\nexport type { ControllerRegistrationOptions } from './codegen/index.js';\nexport { generateRuntime } from './codegen/index.js';\nexport type { RuntimeGeneratorOptions } from './codegen/index.js';\nexport { generateRendererViewManifest } from './codegen/index.js';\nexport type { RendererViewManifestGeneratorOptions } from './codegen/index.js';\nexport { generateRendererControllerRegistration } from './codegen/index.js';\nexport type { RendererControllerRegistrationOptions } from './codegen/index.js';\nexport { generateRendererApp } from './codegen/index.js';\nexport type { RendererAppGeneratorOptions } from './codegen/index.js';\n\n// Window\nexport { WindowManager, WindowStateStore } from './window/index.js';\nexport type { ScreenLike, WindowBounds } from './window/index.js';\n\n// Loader\nexport { LoaderRunner } from './loader/index.js';\n\n// Bridge\nexport { BackendBridge, startBackendLoop, pushEvent } from './bridge/index.js';\n\n// Dev\nexport {\n WoodDevServer,\n BackendWatcher,\n YamlWatcher,\n DEFAULT_WOOD_REMOTE_DEBUGGING_PORT,\n WOOD_DEV_DIRECTORY,\n WOOD_DEV_METADATA_BASENAME,\n resolveWoodRemoteDebuggingPort,\n resolveWoodDevDirectory,\n resolveWoodDevMetadataPath,\n writeWoodDevMetadata,\n readWoodDevMetadata,\n removeWoodDevMetadata,\n} from './dev/index.js';\nexport type { WoodDevMetadata } from './dev/index.js';\n\n// Runtime\nexport {\n getContainer,\n clearContainerRegistryForTests,\n getApplicationRoot,\n setApplicationRoot,\n clearApplicationRootForTests,\n runtime,\n} from './runtime/index.js';\nexport type {\n GetContainerOptions,\n RuntimeOptions,\n RuntimeResult,\n RegisterRuntimeRouter,\n} from './runtime';\n\n// Navigation\nexport { Navigation, getNavigation, go, goto, goback } from './navigation/index.js';\nexport type { NavigationEntry, NavigationOptions } from './navigation/index.js';\n\n// Isomorphic IPC API\nexport { Ipc, getIpc } from './ipc/index.js';\nexport type { IpcPushOptions } from './ipc/index.js';\n\n// Tracing\nexport {\n FrameworkTracer,\n MainTracer,\n RendererTracer,\n TestTracer,\n TraceProvider,\n TraceProviderConfiguration,\n TraceCapture,\n clearTraceHubForTests,\n createTraceCapture,\n getTraceEvents$,\n setRendererTraceEnabled,\n setRendererTraceTransport,\n} from './tracing/index.js';\nexport type {\n TraceCaptureOptions,\n TraceDispatchResult,\n TraceEvent,\n TraceInput,\n TraceLevel,\n TraceProcess,\n TraceProviderMode,\n TraceRuntime,\n TraceWaitOptions,\n} from './tracing/index.js';\n\n// Testing — available via '@noego/wood/testing' subpath export.\n// Not re-exported here to avoid pulling vitest into production builds.\n"],"mappings":"AAoCA,SAAS,eAAe,qBAAqB,8BAA8B;AAG3E,SAAS,mBAAmB;AAG5B,SAAS,iBAAiB,2BAA2B;AACrD,SAAS,YAAY,sBAAsB;AAG3C,SAAS,kBAAkB;AAG3B,SAAS,uBAAuB;AAGhC,SAAS,oBAAoB,wBAAwB,yBAAyB;AAG9E,SAAS,oBAAoB,qBAAqB,kCAAkC;AAIpF,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,wBAAwB;AACjC,SAAS,sCAAsC;AAE/C,SAAS,uBAAuB;AAEhC,SAAS,oCAAoC;AAE7C,SAAS,8CAA8C;AAEvD,SAAS,2BAA2B;AAIpC,SAAS,eAAe,wBAAwB;AAIhD,SAAS,oBAAoB;AAG7B,SAAS,eAAe,kBAAkB,iBAAiB;AAG3D;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AASP,SAAS,YAAY,eAAe,IAAI,MAAM,cAAc;AAI5D,SAAS,KAAK,cAAc;AAI5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":[]}
|
|
@@ -51,8 +51,8 @@ class Navigation {
|
|
|
51
51
|
}
|
|
52
52
|
return { ...current.params };
|
|
53
53
|
}
|
|
54
|
-
replace(page, params = {}, query = {}) {
|
|
55
|
-
const entry = this.createEntry(page, params, query);
|
|
54
|
+
replace(page, params = {}, query = {}, options = {}) {
|
|
55
|
+
const entry = this.createEntry(page, params, query, options);
|
|
56
56
|
if (this.index < 0) {
|
|
57
57
|
this.entries.push(entry);
|
|
58
58
|
this.index = 0;
|
|
@@ -67,13 +67,14 @@ class Navigation {
|
|
|
67
67
|
payload: {
|
|
68
68
|
page: entry.page,
|
|
69
69
|
params: entry.params,
|
|
70
|
-
query: entry.query
|
|
70
|
+
query: entry.query,
|
|
71
|
+
options: entry.options
|
|
71
72
|
}
|
|
72
73
|
});
|
|
73
74
|
return this.cloneEntry(entry);
|
|
74
75
|
}
|
|
75
|
-
go(page, params = {}, query = {}) {
|
|
76
|
-
const entry = this.createEntry(page, params, query);
|
|
76
|
+
go(page, params = {}, query = {}, options = {}) {
|
|
77
|
+
const entry = this.createEntry(page, params, query, options);
|
|
77
78
|
if (this.index < this.entries.length - 1) {
|
|
78
79
|
this.entries = this.entries.slice(0, this.index + 1);
|
|
79
80
|
}
|
|
@@ -87,7 +88,8 @@ class Navigation {
|
|
|
87
88
|
payload: {
|
|
88
89
|
page: entry.page,
|
|
89
90
|
params: entry.params,
|
|
90
|
-
query: entry.query
|
|
91
|
+
query: entry.query,
|
|
92
|
+
options: entry.options
|
|
91
93
|
}
|
|
92
94
|
});
|
|
93
95
|
return this.cloneEntry(entry);
|
|
@@ -136,18 +138,20 @@ class Navigation {
|
|
|
136
138
|
listener(current);
|
|
137
139
|
}
|
|
138
140
|
}
|
|
139
|
-
createEntry(page, params, query) {
|
|
141
|
+
createEntry(page, params, query, options) {
|
|
140
142
|
return {
|
|
141
143
|
page,
|
|
142
144
|
params: this.normalizeRecord(params),
|
|
143
|
-
query: this.normalizeRecord(query)
|
|
145
|
+
query: this.normalizeRecord(query),
|
|
146
|
+
options: { ...options }
|
|
144
147
|
};
|
|
145
148
|
}
|
|
146
149
|
cloneEntry(entry) {
|
|
147
150
|
return {
|
|
148
151
|
page: entry.page,
|
|
149
152
|
params: { ...entry.params },
|
|
150
|
-
query: { ...entry.query }
|
|
153
|
+
query: { ...entry.query },
|
|
154
|
+
options: { ...entry.options }
|
|
151
155
|
};
|
|
152
156
|
}
|
|
153
157
|
normalizeRecord(input) {
|
|
@@ -165,7 +169,8 @@ class Navigation {
|
|
|
165
169
|
[HISTORY_STATE_MARKER]: true,
|
|
166
170
|
page: entry.page,
|
|
167
171
|
params: { ...entry.params },
|
|
168
|
-
query: { ...entry.query }
|
|
172
|
+
query: { ...entry.query },
|
|
173
|
+
options: { ...entry.options }
|
|
169
174
|
};
|
|
170
175
|
window.history[mode](state, "");
|
|
171
176
|
}
|
|
@@ -183,8 +188,8 @@ function getNavigation() {
|
|
|
183
188
|
function goto(delta) {
|
|
184
189
|
return getNavigation().goto(delta);
|
|
185
190
|
}
|
|
186
|
-
function go(page, params = {}, query = {}) {
|
|
187
|
-
return getNavigation().go(page, params, query);
|
|
191
|
+
function go(page, params = {}, query = {}, options = {}) {
|
|
192
|
+
return getNavigation().go(page, params, query, options);
|
|
188
193
|
}
|
|
189
194
|
function goback() {
|
|
190
195
|
return goto(-1);
|
|
@@ -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}\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 ): NavigationEntry {\n const entry = this.createEntry(page, params, query);\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 },\n });\n return this.cloneEntry(entry);\n }\n\n go(\n page: string,\n params: Record<string, string> = {},\n query: Record<string, string> = {},\n ): NavigationEntry {\n const entry = this.createEntry(page, params, query);\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 },\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 ): NavigationEntry {\n return {\n page,\n params: this.normalizeRecord(params),\n query: this.normalizeRecord(query),\n };\n }\n\n private cloneEntry(entry: NavigationEntry): NavigationEntry {\n return {\n page: entry.page,\n params: { ...entry.params },\n query: { ...entry.query },\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 };\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): NavigationEntry {\n return getNavigation().go(page, params, query);\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"],"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\nexport interface NavigationOptions {\n preserveLayouts?: boolean;\n}\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"],"mappings":"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","names":[]}
|
|
@@ -2,6 +2,10 @@ interface NavigationEntry {
|
|
|
2
2
|
page: string;
|
|
3
3
|
params: Record<string, string>;
|
|
4
4
|
query: Record<string, string>;
|
|
5
|
+
options: NavigationOptions;
|
|
6
|
+
}
|
|
7
|
+
interface NavigationOptions {
|
|
8
|
+
preserveLayouts?: boolean;
|
|
5
9
|
}
|
|
6
10
|
type NavigationListener = (entry: NavigationEntry | null) => void;
|
|
7
11
|
declare class Navigation {
|
|
@@ -11,8 +15,8 @@ declare class Navigation {
|
|
|
11
15
|
getCurrent(): NavigationEntry | null;
|
|
12
16
|
getPages(): NavigationEntry[];
|
|
13
17
|
getParams(): Record<string, string>;
|
|
14
|
-
replace(page: string, params?: Record<string, string>, query?: Record<string, string
|
|
15
|
-
go(page: string, params?: Record<string, string>, query?: Record<string, string
|
|
18
|
+
replace(page: string, params?: Record<string, string>, query?: Record<string, string>, options?: NavigationOptions): NavigationEntry;
|
|
19
|
+
go(page: string, params?: Record<string, string>, query?: Record<string, string>, options?: NavigationOptions): NavigationEntry;
|
|
16
20
|
goto(delta: number): NavigationEntry | null;
|
|
17
21
|
goBack(): NavigationEntry | null;
|
|
18
22
|
goForward(): NavigationEntry | null;
|
|
@@ -26,9 +30,9 @@ declare class Navigation {
|
|
|
26
30
|
}
|
|
27
31
|
declare function getNavigation(): Navigation;
|
|
28
32
|
declare function goto(delta: number): NavigationEntry | null;
|
|
29
|
-
declare function go(page: string, params?: Record<string, string>, query?: Record<string, string
|
|
33
|
+
declare function go(page: string, params?: Record<string, string>, query?: Record<string, string>, options?: NavigationOptions): NavigationEntry;
|
|
30
34
|
declare function goback(): NavigationEntry | null;
|
|
31
35
|
/** Test-only helper to clear the navigation singleton. */
|
|
32
36
|
declare function clearNavigationForTests(): void;
|
|
33
37
|
|
|
34
|
-
export { Navigation, type NavigationEntry, clearNavigationForTests, getNavigation, go, goback, goto };
|
|
38
|
+
export { Navigation, type NavigationEntry, type NavigationOptions, clearNavigationForTests, getNavigation, go, goback, goto };
|
|
@@ -2,6 +2,10 @@ interface NavigationEntry {
|
|
|
2
2
|
page: string;
|
|
3
3
|
params: Record<string, string>;
|
|
4
4
|
query: Record<string, string>;
|
|
5
|
+
options: NavigationOptions;
|
|
6
|
+
}
|
|
7
|
+
interface NavigationOptions {
|
|
8
|
+
preserveLayouts?: boolean;
|
|
5
9
|
}
|
|
6
10
|
type NavigationListener = (entry: NavigationEntry | null) => void;
|
|
7
11
|
declare class Navigation {
|
|
@@ -11,8 +15,8 @@ declare class Navigation {
|
|
|
11
15
|
getCurrent(): NavigationEntry | null;
|
|
12
16
|
getPages(): NavigationEntry[];
|
|
13
17
|
getParams(): Record<string, string>;
|
|
14
|
-
replace(page: string, params?: Record<string, string>, query?: Record<string, string
|
|
15
|
-
go(page: string, params?: Record<string, string>, query?: Record<string, string
|
|
18
|
+
replace(page: string, params?: Record<string, string>, query?: Record<string, string>, options?: NavigationOptions): NavigationEntry;
|
|
19
|
+
go(page: string, params?: Record<string, string>, query?: Record<string, string>, options?: NavigationOptions): NavigationEntry;
|
|
16
20
|
goto(delta: number): NavigationEntry | null;
|
|
17
21
|
goBack(): NavigationEntry | null;
|
|
18
22
|
goForward(): NavigationEntry | null;
|
|
@@ -26,9 +30,9 @@ declare class Navigation {
|
|
|
26
30
|
}
|
|
27
31
|
declare function getNavigation(): Navigation;
|
|
28
32
|
declare function goto(delta: number): NavigationEntry | null;
|
|
29
|
-
declare function go(page: string, params?: Record<string, string>, query?: Record<string, string
|
|
33
|
+
declare function go(page: string, params?: Record<string, string>, query?: Record<string, string>, options?: NavigationOptions): NavigationEntry;
|
|
30
34
|
declare function goback(): NavigationEntry | null;
|
|
31
35
|
/** Test-only helper to clear the navigation singleton. */
|
|
32
36
|
declare function clearNavigationForTests(): void;
|
|
33
37
|
|
|
34
|
-
export { Navigation, type NavigationEntry, clearNavigationForTests, getNavigation, go, goback, goto };
|
|
38
|
+
export { Navigation, type NavigationEntry, type NavigationOptions, clearNavigationForTests, getNavigation, go, goback, goto };
|