@noego/wood 0.2.0 → 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/client/index.cjs +1 -1
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- 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/testing/create_controller_harness.cjs +2 -2
- package/dist/testing/create_controller_harness.cjs.map +1 -1
- package/dist/testing/create_test_router.cjs +1 -1
- package/dist/testing/create_test_router.cjs.map +1 -1
- package/dist/testing/index.cjs +6 -6
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.js +3 -3
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/mock_electron.cjs +59 -39
- package/dist/testing/mock_electron.cjs.map +1 -1
- package/dist/testing/mock_electron.d.cts +2 -2
- package/dist/testing/mock_electron.d.ts +2 -2
- package/dist/testing/mock_electron.js +59 -39
- package/dist/testing/mock_electron.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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/parser/views_parser.ts"],"sourcesContent":["import yaml from 'js-yaml';\nimport { readFileSync } from 'fs';\nimport type {\n ViewDef,\n RawViewsDocument,\n RawLayoutEntry,\n RawLayoutObjectEntry,\n RawLayoutConfig,\n RawLayoutGroupEntry,\n} from '../types';\n\nfunction validateControllerValue(controller: unknown, contextLabel: string): string | undefined {\n if (controller === undefined) return undefined;\n if (typeof controller !== 'string' || controller.trim().length === 0) {\n throw new Error(`${contextLabel} has invalid controller. Expected a non-empty string.`);\n }\n return controller.trim();\n}\n\nfunction parseLayoutEntry(entry: RawLayoutEntry, viewKey: string, index: number): { path: string; controller?: string } {\n if (typeof entry === 'string') {\n const path = entry.trim();\n if (!path) {\n throw new Error(`View \"${viewKey}\" has invalid layout entry at index ${index}. Expected a non-empty path string.`);\n }\n return { path };\n }\n\n const layoutObj = entry as RawLayoutObjectEntry;\n const layoutPath = layoutObj.path ?? layoutObj.view ?? layoutObj.layout;\n if (typeof layoutPath !== 'string' || layoutPath.trim().length === 0) {\n throw new Error(\n `View \"${viewKey}\" has invalid layout object at index ${index}. ` +\n 'Expected one of: path, view, or layout as a non-empty string.',\n );\n }\n\n return {\n path: layoutPath.trim(),\n controller: validateControllerValue(layoutObj.controller, `View \"${viewKey}\" layout[${index}]`),\n };\n}\n\nfunction isLayoutGroupEntry(entry: unknown): entry is RawLayoutGroupEntry {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) return false;\n return Object.prototype.hasOwnProperty.call(entry, 'views');\n}\n\nfunction isLayoutObjectEntry(entry: unknown): entry is RawLayoutObjectEntry {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) return false;\n return (\n Object.prototype.hasOwnProperty.call(entry, 'path') ||\n Object.prototype.hasOwnProperty.call(entry, 'view') ||\n Object.prototype.hasOwnProperty.call(entry, 'layout') ||\n Object.prototype.hasOwnProperty.call(entry, 'controller')\n );\n}\n\nfunction normalizeLayouts(rawLayout: RawLayoutConfig | undefined, viewKey: string): {\n entries: RawLayoutEntry[];\n inheritedController?: string;\n} {\n if (rawLayout === undefined) {\n return { entries: [] };\n }\n\n if (Array.isArray(rawLayout)) {\n return { entries: rawLayout };\n }\n\n if (typeof rawLayout === 'string') {\n return { entries: [rawLayout] };\n }\n\n if (isLayoutGroupEntry(rawLayout)) {\n if (!Array.isArray(rawLayout.views)) {\n throw new Error(`View \"${viewKey}\" has invalid layout object. \"views\" must be an array.`);\n }\n\n return {\n entries: rawLayout.views,\n inheritedController: validateControllerValue(rawLayout.controller, `View \"${viewKey}\" layout`),\n };\n }\n\n if (isLayoutObjectEntry(rawLayout)) {\n return { entries: [rawLayout] };\n }\n\n throw new Error(\n `View \"${viewKey}\" has invalid layout definition. Expected an array, a string path, or an object with \"views\".`,\n );\n}\n\n/**\n * Parse views YAML content into a flat array of ViewDef.\n * Supports Wood-native `view:` format (dot-path keys).\n */\nexport function parseViews(yamlContent: string): ViewDef[] {\n const doc = yaml.load(yamlContent) as RawViewsDocument;\n const views: ViewDef[] = [];\n\n // Wood-native `view:` format\n // First segment = window name, rest = page name\n if (doc.view) {\n for (const [dotPath, entry] of Object.entries(doc.view)) {\n const segments = dotPath.split('.');\n const windowName = segments[0];\n const pageName = segments.slice(1).join('.');\n\n const normalizedLayouts = normalizeLayouts(entry.layout, dotPath);\n const parsedLayouts = normalizedLayouts.entries.map((layoutEntry, index) =>\n parseLayoutEntry(layoutEntry, dotPath, index),\n );\n if (normalizedLayouts.inheritedController) {\n if (parsedLayouts.length === 0) {\n throw new Error(\n `View \"${dotPath}\" sets a layout controller but has no layout views. Define at least one layout entry.`,\n );\n }\n\n const firstLayoutController = parsedLayouts[0].controller;\n if (firstLayoutController && firstLayoutController !== normalizedLayouts.inheritedController) {\n throw new Error(\n `View \"${dotPath}\" has conflicting layout controllers. Use either layout.controller or layout.views[0].controller.`,\n );\n }\n parsedLayouts[0].controller ??= normalizedLayouts.inheritedController;\n }\n\n const layoutPaths = parsedLayouts.map((layout) => layout.path);\n const layoutControllers = parsedLayouts.map((layout) => layout.controller);\n\n const viewController = validateControllerValue(entry.controller, `View \"${dotPath}\"`);\n\n const viewDef: ViewDef = {\n windowName,\n pageName,\n viewPath: entry.view,\n layouts: layoutPaths,\n middleware: entry.middleware,\n controller: viewController,\n };\n\n if (layoutControllers.some((value) => value !== undefined)) {\n viewDef.layoutControllers = layoutControllers;\n }\n\n views.push(viewDef);\n }\n }\n\n return views;\n}\n\n/** Read a YAML file from disk and parse it into ViewDef[]. */\nexport function parseViewsFile(filePath: string): ViewDef[] {\n const content = readFileSync(filePath, 'utf-8');\n return parseViews(content);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/parser/views_parser.ts"],"sourcesContent":["import yaml from 'js-yaml';\nimport { readFileSync } from 'fs';\nimport type {\n ViewDef,\n RawViewsDocument,\n RawLayoutEntry,\n RawLayoutObjectEntry,\n RawLayoutConfig,\n RawLayoutGroupEntry,\n} from '../types';\n\nfunction validateControllerValue(controller: unknown, contextLabel: string): string | undefined {\n if (controller === undefined) return undefined;\n if (typeof controller !== 'string' || controller.trim().length === 0) {\n throw new Error(`${contextLabel} has invalid controller. Expected a non-empty string.`);\n }\n return controller.trim();\n}\n\nfunction validatePreserveValue(preserve: unknown, contextLabel: string): boolean {\n if (preserve === undefined) return false;\n if (typeof preserve !== 'boolean') {\n throw new Error(`${contextLabel} has invalid preserve. Expected a boolean.`);\n }\n return preserve;\n}\n\nfunction parseLayoutEntry(entry: RawLayoutEntry, viewKey: string, index: number): { path: string; controller?: string; preserve: boolean } {\n if (typeof entry === 'string') {\n const path = entry.trim();\n if (!path) {\n throw new Error(`View \"${viewKey}\" has invalid layout entry at index ${index}. Expected a non-empty path string.`);\n }\n return { path, preserve: false };\n }\n\n const layoutObj = entry as RawLayoutObjectEntry;\n const layoutPath = layoutObj.path ?? layoutObj.view ?? layoutObj.layout;\n if (typeof layoutPath !== 'string' || layoutPath.trim().length === 0) {\n throw new Error(\n `View \"${viewKey}\" has invalid layout object at index ${index}. ` +\n 'Expected one of: path, view, or layout as a non-empty string.',\n );\n }\n\n return {\n path: layoutPath.trim(),\n controller: validateControllerValue(layoutObj.controller, `View \"${viewKey}\" layout[${index}]`),\n preserve: validatePreserveValue(layoutObj.preserve, `View \"${viewKey}\" layout[${index}]`),\n };\n}\n\nfunction isLayoutGroupEntry(entry: unknown): entry is RawLayoutGroupEntry {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) return false;\n return Object.prototype.hasOwnProperty.call(entry, 'views');\n}\n\nfunction isLayoutObjectEntry(entry: unknown): entry is RawLayoutObjectEntry {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) return false;\n return (\n Object.prototype.hasOwnProperty.call(entry, 'path') ||\n Object.prototype.hasOwnProperty.call(entry, 'view') ||\n Object.prototype.hasOwnProperty.call(entry, 'layout') ||\n Object.prototype.hasOwnProperty.call(entry, 'controller')\n );\n}\n\nfunction normalizeLayouts(rawLayout: RawLayoutConfig | undefined, viewKey: string): {\n entries: RawLayoutEntry[];\n inheritedController?: string;\n inheritedPreserve?: boolean;\n} {\n if (rawLayout === undefined) {\n return { entries: [] };\n }\n\n if (Array.isArray(rawLayout)) {\n return { entries: rawLayout };\n }\n\n if (typeof rawLayout === 'string') {\n return { entries: [rawLayout] };\n }\n\n if (isLayoutGroupEntry(rawLayout)) {\n if (!Array.isArray(rawLayout.views)) {\n throw new Error(`View \"${viewKey}\" has invalid layout object. \"views\" must be an array.`);\n }\n\n return {\n entries: rawLayout.views,\n inheritedController: validateControllerValue(rawLayout.controller, `View \"${viewKey}\" layout`),\n inheritedPreserve: validatePreserveValue(rawLayout.preserve, `View \"${viewKey}\" layout`),\n };\n }\n\n if (isLayoutObjectEntry(rawLayout)) {\n return { entries: [rawLayout] };\n }\n\n throw new Error(\n `View \"${viewKey}\" has invalid layout definition. Expected an array, a string path, or an object with \"views\".`,\n );\n}\n\n/**\n * Parse views YAML content into a flat array of ViewDef.\n * Supports Wood-native `view:` format (dot-path keys).\n */\nexport function parseViews(yamlContent: string): ViewDef[] {\n const doc = yaml.load(yamlContent) as RawViewsDocument;\n const views: ViewDef[] = [];\n\n // Wood-native `view:` format\n // First segment = window name, rest = page name\n if (doc.view) {\n for (const [dotPath, entry] of Object.entries(doc.view)) {\n const segments = dotPath.split('.');\n const windowName = segments[0];\n const pageName = segments.slice(1).join('.');\n\n const normalizedLayouts = normalizeLayouts(entry.layout, dotPath);\n const parsedLayouts = normalizedLayouts.entries.map((layoutEntry, index) =>\n parseLayoutEntry(layoutEntry, dotPath, index),\n );\n if (normalizedLayouts.inheritedController) {\n if (parsedLayouts.length === 0) {\n throw new Error(\n `View \"${dotPath}\" sets a layout controller but has no layout views. Define at least one layout entry.`,\n );\n }\n\n const firstLayoutController = parsedLayouts[0].controller;\n if (firstLayoutController && firstLayoutController !== normalizedLayouts.inheritedController) {\n throw new Error(\n `View \"${dotPath}\" has conflicting layout controllers. Use either layout.controller or layout.views[0].controller.`,\n );\n }\n parsedLayouts[0].controller ??= normalizedLayouts.inheritedController;\n }\n if (normalizedLayouts.inheritedPreserve) {\n if (parsedLayouts.length === 0) {\n throw new Error(\n `View \"${dotPath}\" sets layout preserve but has no layout views. Define at least one layout entry.`,\n );\n }\n parsedLayouts[0].preserve = true;\n }\n\n const layoutPaths = parsedLayouts.map((layout) => layout.path);\n const layoutControllers = parsedLayouts.map((layout) => layout.controller);\n const layoutPreserve = parsedLayouts.map((layout) => layout.preserve);\n\n const viewController = validateControllerValue(entry.controller, `View \"${dotPath}\"`);\n\n const viewDef: ViewDef = {\n windowName,\n pageName,\n viewPath: entry.view,\n layouts: layoutPaths,\n middleware: entry.middleware,\n controller: viewController,\n };\n\n if (layoutControllers.some((value) => value !== undefined)) {\n viewDef.layoutControllers = layoutControllers;\n }\n if (layoutPreserve.some((value) => value)) {\n viewDef.layoutPreserve = layoutPreserve;\n }\n\n views.push(viewDef);\n }\n }\n\n return views;\n}\n\n/** Read a YAML file from disk and parse it into ViewDef[]. */\nexport function parseViewsFile(filePath: string): ViewDef[] {\n const content = readFileSync(filePath, 'utf-8');\n return parseViews(content);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -28,8 +28,8 @@ var import_navigation = require("../navigation/index.js");
|
|
|
28
28
|
var import_tracing = require("../tracing/index.js");
|
|
29
29
|
var import_operations_parser = require("../parser/operations_parser.cjs");
|
|
30
30
|
var import_controller_lifecycle = require("../controller/controller_lifecycle.cjs");
|
|
31
|
-
var import_create_router_bridge = require("./create_router_bridge.
|
|
32
|
-
var import_create_test_router = require("./create_test_router.
|
|
31
|
+
var import_create_router_bridge = require("./create_router_bridge.js");
|
|
32
|
+
var import_create_test_router = require("./create_test_router.js");
|
|
33
33
|
function readOperations(input) {
|
|
34
34
|
if (input.includes("\n") || input.includes(":")) {
|
|
35
35
|
return (0, import_operations_parser.parseOperations)(input);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/testing/create_controller_harness.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport {\n App,\n clearClientAppForTests,\n clearClientContainerForTests,\n clearClientLoggersForTests,\n clearClientNavigationForTests,\n clearClientWindowControlsForTests,\n getApp,\n getWindowControls,\n Ipc,\n WOOD_INTERNAL_BRIDGE_KEY,\n} from '../client/index.js';\nimport { getIpc } from '../ipc/index.js';\nimport { Navigation, getNavigation } from '../navigation/index.js';\nimport { TraceProvider, TraceProviderConfiguration } from '../tracing/index.js';\nimport { parseOperations } from '../parser/operations_parser.cjs';\nimport type { OperationDef } from '../types/operations.cjs';\nimport { disposeControllerLifecycle } from '../controller/controller_lifecycle.cjs';\nimport { createRouterBridge, type RouterBridgeResult } from './create_router_bridge.cjs';\nimport { createTestRouter } from './create_test_router.cjs';\n\nexport interface CreateControllerHarnessOptions<T> {\n controllerClass: new (...args: any[]) => T;\n container: any;\n operations: string | string[];\n controllersDir: string;\n middlewareDir?: string;\n configureContainer?: (container: any) => void | Promise<void>;\n configureRouter?: (router: ReturnType<typeof createTestRouter>['router']) => void | Promise<void>;\n prepareClient?: (context: {\n bridge: Record<string, any>;\n events: RouterBridgeResult['events'];\n navigation: Navigation;\n container: any;\n }) => void | Promise<void>;\n initialize?: boolean;\n}\n\nexport interface ControllerHarnessResult<T> extends RouterBridgeResult {\n controller: T;\n container: any;\n router: ReturnType<typeof createTestRouter>['router'];\n navigation: Navigation;\n trace: TraceProvider;\n destroy: () => void | Promise<void>;\n}\n\ntype MutableGlobal = typeof globalThis & {\n [WOOD_INTERNAL_BRIDGE_KEY]?: unknown;\n wood?: unknown;\n};\n\nfunction readOperations(input: string): Map<string, OperationDef> {\n if (input.includes('\\n') || input.includes(':')) {\n return parseOperations(input);\n }\n\n return parseOperations(readFileSync(input, 'utf-8'));\n}\n\nfunction mergeOperations(inputs: string | string[]): Map<string, OperationDef> {\n const merged = new Map<string, OperationDef>();\n\n for (const input of Array.isArray(inputs) ? inputs : [inputs]) {\n for (const [channel, operation] of readOperations(input)) {\n merged.set(channel, operation);\n }\n }\n\n return merged;\n}\n\nfunction createRpcManifest(operations: Map<string, OperationDef>) {\n return Array.from(operations.values()).map((operation) => ({\n channel: operation.channel,\n controller: operation.controller,\n action: operation.action,\n path: operation.channel.split('.'),\n hasInput: !!operation.inputSchema,\n }));\n}\n\nfunction registerClientBuiltins(container: any): void {\n if (typeof container.registerFunction !== 'function') {\n return;\n }\n\n const traceConfiguration = new TraceProviderConfiguration();\n traceConfiguration.configureMode('test');\n traceConfiguration.configureRuntime('renderer');\n traceConfiguration.configureEnabled(true);\n\n container.registerFunction(Navigation, () => getNavigation());\n container.registerFunction(App, () => getApp());\n container.registerFunction(Ipc, () => getIpc());\n container.registerFunction(WindowControls, () => getWindowControls());\n container.registerFunction(TraceProviderConfiguration, () => traceConfiguration);\n}\n\nclass WindowControls {\n async open(_windowId: string, _options?: Record<string, unknown>): Promise<void> {}\n async close(_windowId?: string): Promise<void> {}\n async focus(_windowId: string): Promise<void> {}\n async minimize(_windowId?: string): Promise<void> {}\n async maximize(_windowId?: string): Promise<void> {}\n}\n\nexport async function createControllerHarness<T>(\n options: CreateControllerHarnessOptions<T>,\n): Promise<ControllerHarnessResult<T>> {\n await options.configureContainer?.(options.container);\n\n if (typeof options.container.instance === 'function') {\n const rootTraceConfiguration = await options.container.instance(TraceProviderConfiguration);\n rootTraceConfiguration.configureMode('test');\n rootTraceConfiguration.configureRuntime('main');\n }\n\n const operations = mergeOperations(options.operations);\n const { router } = createTestRouter('', {\n container: options.container,\n controllersDir: options.controllersDir,\n middlewareDir: options.middlewareDir,\n });\n router.loadOperations(operations);\n await options.configureRouter?.(router);\n\n const { bridge, events } = createRouterBridge(router);\n const harnessBridge = Object.assign(bridge, {\n __rpcManifest: createRpcManifest(operations),\n });\n\n const globalObj = globalThis as MutableGlobal;\n const previousInternalBridge = globalObj[WOOD_INTERNAL_BRIDGE_KEY];\n const previousWoodBridge = globalObj.wood;\n globalObj[WOOD_INTERNAL_BRIDGE_KEY] = harnessBridge;\n globalObj.wood = harnessBridge;\n\n clearClientContainerForTests();\n clearClientAppForTests();\n clearClientNavigationForTests();\n clearClientWindowControlsForTests();\n clearClientLoggersForTests();\n\n const scopedContainer = options.container.extend();\n registerClientBuiltins(scopedContainer);\n if (typeof scopedContainer.registerClass === 'function') {\n scopedContainer.registerClass(options.controllerClass);\n }\n const navigation = getNavigation();\n await options.prepareClient?.({\n bridge: harnessBridge,\n events,\n navigation,\n container: scopedContainer,\n });\n\n const controller = await scopedContainer.instance(options.controllerClass);\n const trace = await scopedContainer.instance(TraceProvider);\n if (options.initialize && typeof (controller as { initialize?: () => void }).initialize === 'function') {\n await Promise.resolve(\n (controller as { initialize: () => void | Promise<void> }).initialize(),\n );\n }\n\n trace.info({\n source: 'wood.testing.controller-harness',\n type: 'harness.created',\n payload: {\n controllerClass: options.controllerClass.name,\n },\n });\n\n return {\n controller,\n bridge: harnessBridge,\n events,\n router,\n container: scopedContainer,\n navigation,\n trace,\n destroy: async () => {\n trace.info({\n source: 'wood.testing.controller-harness',\n type: 'harness.destroyed',\n });\n await disposeControllerLifecycle(controller);\n events.clear();\n clearClientContainerForTests();\n clearClientAppForTests();\n clearClientNavigationForTests();\n clearClientWindowControlsForTests();\n clearClientLoggersForTests();\n\n if (previousInternalBridge === undefined) {\n delete globalObj[WOOD_INTERNAL_BRIDGE_KEY];\n } else {\n globalObj[WOOD_INTERNAL_BRIDGE_KEY] = previousInternalBridge;\n }\n\n if (previousWoodBridge === undefined) {\n delete globalObj.wood;\n } else {\n globalObj.wood = previousWoodBridge;\n }\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA6B;AAC7B,oBAWO;AACP,iBAAuB;AACvB,wBAA0C;AAC1C,qBAA0D;AAC1D,+BAAgC;AAEhC,kCAA2C;AAC3C,kCAA4D;AAC5D,gCAAiC;AAiCjC,SAAS,eAAe,OAA0C;AAChE,MAAI,MAAM,SAAS,IAAI,KAAK,MAAM,SAAS,GAAG,GAAG;AAC/C,eAAO,0CAAgB,KAAK;AAAA,EAC9B;AAEA,aAAO,8CAAgB,6BAAa,OAAO,OAAO,CAAC;AACrD;AAEA,SAAS,gBAAgB,QAAsD;AAC7E,QAAM,SAAS,oBAAI,IAA0B;AAE7C,aAAW,SAAS,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAM,GAAG;AAC7D,eAAW,CAAC,SAAS,SAAS,KAAK,eAAe,KAAK,GAAG;AACxD,aAAO,IAAI,SAAS,SAAS;AAAA,IAC/B;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,kBAAkB,YAAuC;AAChE,SAAO,MAAM,KAAK,WAAW,OAAO,CAAC,EAAE,IAAI,CAAC,eAAe;AAAA,IACzD,SAAS,UAAU;AAAA,IACnB,YAAY,UAAU;AAAA,IACtB,QAAQ,UAAU;AAAA,IAClB,MAAM,UAAU,QAAQ,MAAM,GAAG;AAAA,IACjC,UAAU,CAAC,CAAC,UAAU;AAAA,EACxB,EAAE;AACJ;AAEA,SAAS,uBAAuB,WAAsB;AACpD,MAAI,OAAO,UAAU,qBAAqB,YAAY;AACpD;AAAA,EACF;AAEA,QAAM,qBAAqB,IAAI,0CAA2B;AAC1D,qBAAmB,cAAc,MAAM;AACvC,qBAAmB,iBAAiB,UAAU;AAC9C,qBAAmB,iBAAiB,IAAI;AAExC,YAAU,iBAAiB,8BAAY,UAAM,iCAAc,CAAC;AAC5D,YAAU,iBAAiB,mBAAK,UAAM,sBAAO,CAAC;AAC9C,YAAU,iBAAiB,mBAAK,UAAM,mBAAO,CAAC;AAC9C,YAAU,iBAAiB,gBAAgB,UAAM,iCAAkB,CAAC;AACpE,YAAU,iBAAiB,2CAA4B,MAAM,kBAAkB;AACjF;AAEA,MAAM,eAAe;AAAA,EACnB,MAAM,KAAK,WAAmB,UAAmD;AAAA,EAAC;AAAA,EAClF,MAAM,MAAM,WAAmC;AAAA,EAAC;AAAA,EAChD,MAAM,MAAM,WAAkC;AAAA,EAAC;AAAA,EAC/C,MAAM,SAAS,WAAmC;AAAA,EAAC;AAAA,EACnD,MAAM,SAAS,WAAmC;AAAA,EAAC;AACrD;AAEA,eAAsB,wBACpB,SACqC;AACrC,QAAM,QAAQ,qBAAqB,QAAQ,SAAS;AAEpD,MAAI,OAAO,QAAQ,UAAU,aAAa,YAAY;AACpD,UAAM,yBAAyB,MAAM,QAAQ,UAAU,SAAS,yCAA0B;AAC1F,2BAAuB,cAAc,MAAM;AAC3C,2BAAuB,iBAAiB,MAAM;AAAA,EAChD;AAEA,QAAM,aAAa,gBAAgB,QAAQ,UAAU;AACrD,QAAM,EAAE,OAAO,QAAI,4CAAiB,IAAI;AAAA,IACtC,WAAW,QAAQ;AAAA,IACnB,gBAAgB,QAAQ;AAAA,IACxB,eAAe,QAAQ;AAAA,EACzB,CAAC;AACD,SAAO,eAAe,UAAU;AAChC,QAAM,QAAQ,kBAAkB,MAAM;AAEtC,QAAM,EAAE,QAAQ,OAAO,QAAI,gDAAmB,MAAM;AACpD,QAAM,gBAAgB,OAAO,OAAO,QAAQ;AAAA,IAC1C,eAAe,kBAAkB,UAAU;AAAA,EAC7C,CAAC;AAED,QAAM,YAAY;AAClB,QAAM,yBAAyB,UAAU,sCAAwB;AACjE,QAAM,qBAAqB,UAAU;AACrC,YAAU,sCAAwB,IAAI;AACtC,YAAU,OAAO;AAEjB,kDAA6B;AAC7B,4CAAuB;AACvB,mDAA8B;AAC9B,uDAAkC;AAClC,gDAA2B;AAE3B,QAAM,kBAAkB,QAAQ,UAAU,OAAO;AACjD,yBAAuB,eAAe;AACtC,MAAI,OAAO,gBAAgB,kBAAkB,YAAY;AACvD,oBAAgB,cAAc,QAAQ,eAAe;AAAA,EACvD;AACA,QAAM,iBAAa,iCAAc;AACjC,QAAM,QAAQ,gBAAgB;AAAA,IAC5B,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA,WAAW;AAAA,EACb,CAAC;AAED,QAAM,aAAa,MAAM,gBAAgB,SAAS,QAAQ,eAAe;AACzE,QAAM,QAAQ,MAAM,gBAAgB,SAAS,4BAAa;AAC1D,MAAI,QAAQ,cAAc,OAAQ,WAA2C,eAAe,YAAY;AACtG,UAAM,QAAQ;AAAA,MACX,WAA0D,WAAW;AAAA,IACxE;AAAA,EACF;AAEA,QAAM,KAAK;AAAA,IACT,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,SAAS;AAAA,MACP,iBAAiB,QAAQ,gBAAgB;AAAA,IAC3C;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA,SAAS,YAAY;AACnB,YAAM,KAAK;AAAA,QACT,QAAQ;AAAA,QACR,MAAM;AAAA,MACR,CAAC;AACD,gBAAM,wDAA2B,UAAU;AAC3C,aAAO,MAAM;AACb,sDAA6B;AAC7B,gDAAuB;AACvB,uDAA8B;AAC9B,2DAAkC;AAClC,oDAA2B;AAE3B,UAAI,2BAA2B,QAAW;AACxC,eAAO,UAAU,sCAAwB;AAAA,MAC3C,OAAO;AACL,kBAAU,sCAAwB,IAAI;AAAA,MACxC;AAEA,UAAI,uBAAuB,QAAW;AACpC,eAAO,UAAU;AAAA,MACnB,OAAO;AACL,kBAAU,OAAO;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/testing/create_controller_harness.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport {\n App,\n clearClientAppForTests,\n clearClientContainerForTests,\n clearClientLoggersForTests,\n clearClientNavigationForTests,\n clearClientWindowControlsForTests,\n getApp,\n getWindowControls,\n Ipc,\n WOOD_INTERNAL_BRIDGE_KEY,\n} from '../client/index.js';\nimport { getIpc } from '../ipc/index.js';\nimport { Navigation, getNavigation } from '../navigation/index.js';\nimport { TraceProvider, TraceProviderConfiguration } from '../tracing/index.js';\nimport { parseOperations } from '../parser/operations_parser.cjs';\nimport type { OperationDef } from '../types/operations.cjs';\nimport { disposeControllerLifecycle } from '../controller/controller_lifecycle.cjs';\nimport { createRouterBridge, type RouterBridgeResult } from './create_router_bridge.js';\nimport { createTestRouter } from './create_test_router.js';\n\nexport interface CreateControllerHarnessOptions<T> {\n controllerClass: new (...args: any[]) => T;\n container: any;\n operations: string | string[];\n controllersDir: string;\n middlewareDir?: string;\n configureContainer?: (container: any) => void | Promise<void>;\n configureRouter?: (router: ReturnType<typeof createTestRouter>['router']) => void | Promise<void>;\n prepareClient?: (context: {\n bridge: Record<string, any>;\n events: RouterBridgeResult['events'];\n navigation: Navigation;\n container: any;\n }) => void | Promise<void>;\n initialize?: boolean;\n}\n\nexport interface ControllerHarnessResult<T> extends RouterBridgeResult {\n controller: T;\n container: any;\n router: ReturnType<typeof createTestRouter>['router'];\n navigation: Navigation;\n trace: TraceProvider;\n destroy: () => void | Promise<void>;\n}\n\ntype MutableGlobal = typeof globalThis & {\n [WOOD_INTERNAL_BRIDGE_KEY]?: unknown;\n wood?: unknown;\n};\n\nfunction readOperations(input: string): Map<string, OperationDef> {\n if (input.includes('\\n') || input.includes(':')) {\n return parseOperations(input);\n }\n\n return parseOperations(readFileSync(input, 'utf-8'));\n}\n\nfunction mergeOperations(inputs: string | string[]): Map<string, OperationDef> {\n const merged = new Map<string, OperationDef>();\n\n for (const input of Array.isArray(inputs) ? inputs : [inputs]) {\n for (const [channel, operation] of readOperations(input)) {\n merged.set(channel, operation);\n }\n }\n\n return merged;\n}\n\nfunction createRpcManifest(operations: Map<string, OperationDef>) {\n return Array.from(operations.values()).map((operation) => ({\n channel: operation.channel,\n controller: operation.controller,\n action: operation.action,\n path: operation.channel.split('.'),\n hasInput: !!operation.inputSchema,\n }));\n}\n\nfunction registerClientBuiltins(container: any): void {\n if (typeof container.registerFunction !== 'function') {\n return;\n }\n\n const traceConfiguration = new TraceProviderConfiguration();\n traceConfiguration.configureMode('test');\n traceConfiguration.configureRuntime('renderer');\n traceConfiguration.configureEnabled(true);\n\n container.registerFunction(Navigation, () => getNavigation());\n container.registerFunction(App, () => getApp());\n container.registerFunction(Ipc, () => getIpc());\n container.registerFunction(WindowControls, () => getWindowControls());\n container.registerFunction(TraceProviderConfiguration, () => traceConfiguration);\n}\n\nclass WindowControls {\n async open(_windowId: string, _options?: Record<string, unknown>): Promise<void> {}\n async close(_windowId?: string): Promise<void> {}\n async focus(_windowId: string): Promise<void> {}\n async minimize(_windowId?: string): Promise<void> {}\n async maximize(_windowId?: string): Promise<void> {}\n}\n\nexport async function createControllerHarness<T>(\n options: CreateControllerHarnessOptions<T>,\n): Promise<ControllerHarnessResult<T>> {\n await options.configureContainer?.(options.container);\n\n if (typeof options.container.instance === 'function') {\n const rootTraceConfiguration = await options.container.instance(TraceProviderConfiguration);\n rootTraceConfiguration.configureMode('test');\n rootTraceConfiguration.configureRuntime('main');\n }\n\n const operations = mergeOperations(options.operations);\n const { router } = createTestRouter('', {\n container: options.container,\n controllersDir: options.controllersDir,\n middlewareDir: options.middlewareDir,\n });\n router.loadOperations(operations);\n await options.configureRouter?.(router);\n\n const { bridge, events } = createRouterBridge(router);\n const harnessBridge = Object.assign(bridge, {\n __rpcManifest: createRpcManifest(operations),\n });\n\n const globalObj = globalThis as MutableGlobal;\n const previousInternalBridge = globalObj[WOOD_INTERNAL_BRIDGE_KEY];\n const previousWoodBridge = globalObj.wood;\n globalObj[WOOD_INTERNAL_BRIDGE_KEY] = harnessBridge;\n globalObj.wood = harnessBridge;\n\n clearClientContainerForTests();\n clearClientAppForTests();\n clearClientNavigationForTests();\n clearClientWindowControlsForTests();\n clearClientLoggersForTests();\n\n const scopedContainer = options.container.extend();\n registerClientBuiltins(scopedContainer);\n if (typeof scopedContainer.registerClass === 'function') {\n scopedContainer.registerClass(options.controllerClass);\n }\n const navigation = getNavigation();\n await options.prepareClient?.({\n bridge: harnessBridge,\n events,\n navigation,\n container: scopedContainer,\n });\n\n const controller = await scopedContainer.instance(options.controllerClass);\n const trace = await scopedContainer.instance(TraceProvider);\n if (options.initialize && typeof (controller as { initialize?: () => void }).initialize === 'function') {\n await Promise.resolve(\n (controller as { initialize: () => void | Promise<void> }).initialize(),\n );\n }\n\n trace.info({\n source: 'wood.testing.controller-harness',\n type: 'harness.created',\n payload: {\n controllerClass: options.controllerClass.name,\n },\n });\n\n return {\n controller,\n bridge: harnessBridge,\n events,\n router,\n container: scopedContainer,\n navigation,\n trace,\n destroy: async () => {\n trace.info({\n source: 'wood.testing.controller-harness',\n type: 'harness.destroyed',\n });\n await disposeControllerLifecycle(controller);\n events.clear();\n clearClientContainerForTests();\n clearClientAppForTests();\n clearClientNavigationForTests();\n clearClientWindowControlsForTests();\n clearClientLoggersForTests();\n\n if (previousInternalBridge === undefined) {\n delete globalObj[WOOD_INTERNAL_BRIDGE_KEY];\n } else {\n globalObj[WOOD_INTERNAL_BRIDGE_KEY] = previousInternalBridge;\n }\n\n if (previousWoodBridge === undefined) {\n delete globalObj.wood;\n } else {\n globalObj.wood = previousWoodBridge;\n }\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -23,7 +23,7 @@ __export(create_test_router_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(create_test_router_exports);
|
|
24
24
|
var import_wood_router = require("../router/wood_router.cjs");
|
|
25
25
|
var import_operations_parser = require("../parser/operations_parser.cjs");
|
|
26
|
-
var import_create_test_container = require("./create_test_container.
|
|
26
|
+
var import_create_test_container = require("./create_test_container.js");
|
|
27
27
|
var import_fs = require("fs");
|
|
28
28
|
function createTestRouter(yamlPathOrContent, options) {
|
|
29
29
|
let operations;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/testing/create_test_router.ts"],"sourcesContent":["import { WoodRouter } from '../router/wood_router.cjs';\nimport { parseOperations } from '../parser/operations_parser.cjs';\nimport { createTestContainer } from './create_test_container.
|
|
1
|
+
{"version":3,"sources":["../../src/testing/create_test_router.ts"],"sourcesContent":["import { WoodRouter } from '../router/wood_router.cjs';\nimport { parseOperations } from '../parser/operations_parser.cjs';\nimport { createTestContainer } from './create_test_container.js';\nimport { readFileSync } from 'fs';\n\nexport interface TestRouterResult {\n router: WoodRouter;\n dispatch: (channel: string, data?: unknown) => Promise<unknown>;\n channels: string[];\n}\n\n/**\n * Create a WoodRouter from operations YAML, ready for integration testing.\n * No real ipcMain -- operations are callable via dispatch().\n */\nexport function createTestRouter(\n yamlPathOrContent: string,\n options?: {\n container?: any;\n controllersDir?: string;\n middlewareDir?: string;\n },\n): TestRouterResult {\n // Parse operations\n let operations: Map<string, any>;\n if (yamlPathOrContent.trim() === '') {\n operations = new Map();\n } else if (yamlPathOrContent.includes('\\n') || yamlPathOrContent.includes(':')) {\n // Looks like YAML content\n operations = parseOperations(yamlPathOrContent);\n } else {\n // Looks like a file path\n const content = readFileSync(yamlPathOrContent, 'utf-8');\n operations = parseOperations(content);\n }\n\n const container = options?.container ?? createTestContainer();\n\n const router = new WoodRouter({\n container,\n controllersDir: options?.controllersDir ?? './server/controller',\n middlewareDir: options?.middlewareDir ?? './middleware',\n mode: 'dev', // Tests use filesystem-based controller resolution\n });\n\n router.loadOperations(operations);\n\n return {\n router,\n dispatch: (channel: string, data?: unknown) => router.dispatch(channel, data ?? {}),\n channels: router.getChannels(),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAA2B;AAC3B,+BAAgC;AAChC,mCAAoC;AACpC,gBAA6B;AAYtB,SAAS,iBACd,mBACA,SAKkB;AAElB,MAAI;AACJ,MAAI,kBAAkB,KAAK,MAAM,IAAI;AACnC,iBAAa,oBAAI,IAAI;AAAA,EACvB,WAAW,kBAAkB,SAAS,IAAI,KAAK,kBAAkB,SAAS,GAAG,GAAG;AAE9E,qBAAa,0CAAgB,iBAAiB;AAAA,EAChD,OAAO;AAEL,UAAM,cAAU,wBAAa,mBAAmB,OAAO;AACvD,qBAAa,0CAAgB,OAAO;AAAA,EACtC;AAEA,QAAM,YAAY,SAAS,iBAAa,kDAAoB;AAE5D,QAAM,SAAS,IAAI,8BAAW;AAAA,IAC5B;AAAA,IACA,gBAAgB,SAAS,kBAAkB;AAAA,IAC3C,eAAe,SAAS,iBAAiB;AAAA,IACzC,MAAM;AAAA;AAAA,EACR,CAAC;AAED,SAAO,eAAe,UAAU;AAEhC,SAAO;AAAA,IACL;AAAA,IACA,UAAU,CAAC,SAAiB,SAAmB,OAAO,SAAS,SAAS,QAAQ,CAAC,CAAC;AAAA,IAClF,UAAU,OAAO,YAAY;AAAA,EAC/B;AACF;","names":[]}
|
package/dist/testing/index.cjs
CHANGED
|
@@ -30,12 +30,12 @@ __export(testing_exports, {
|
|
|
30
30
|
mockElectron: () => import_mock_electron.mockElectron
|
|
31
31
|
});
|
|
32
32
|
module.exports = __toCommonJS(testing_exports);
|
|
33
|
-
var import_create_test_container = require("./create_test_container.
|
|
34
|
-
var import_create_controller_harness = require("./create_controller_harness");
|
|
35
|
-
var import_create_test_router = require("./create_test_router.
|
|
36
|
-
var import_mock_electron = require("./mock_electron.
|
|
37
|
-
var import_create_router_bridge = require("./create_router_bridge");
|
|
38
|
-
var import_browser = require("./browser");
|
|
33
|
+
var import_create_test_container = require("./create_test_container.js");
|
|
34
|
+
var import_create_controller_harness = require("./create_controller_harness.js");
|
|
35
|
+
var import_create_test_router = require("./create_test_router.js");
|
|
36
|
+
var import_mock_electron = require("./mock_electron.js");
|
|
37
|
+
var import_create_router_bridge = require("./create_router_bridge.js");
|
|
38
|
+
var import_browser = require("./browser.js");
|
|
39
39
|
var import_tracing = require("../tracing/index.js");
|
|
40
40
|
// Annotate the CommonJS export names for ESM import in node:
|
|
41
41
|
0 && (module.exports = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/testing/index.ts"],"sourcesContent":["export { createTestContainer } from './create_test_container.
|
|
1
|
+
{"version":3,"sources":["../../src/testing/index.ts"],"sourcesContent":["export { createTestContainer } from './create_test_container.js';\nexport {\n createControllerHarness,\n type ControllerHarnessResult,\n type CreateControllerHarnessOptions,\n} from './create_controller_harness.js';\nexport { createTestRouter, type TestRouterResult } from './create_test_router.js';\nexport { mockElectron, getElectronMockFactory } from './mock_electron.js';\nexport {\n createRouterBridge,\n RouterBridgeEvents,\n type RouterBridgeResult,\n} from './create_router_bridge.js';\nexport {\n browser,\n createBrowserBridgeFixture,\n type MountedWoodBridge,\n type MountedWoodComponent,\n type MountedWoodNavigation,\n type MountedWoodRoute,\n type MountedWoodSurface,\n type MountedWoodTree,\n type MountComponentOptions,\n type MountRouteOptions,\n type MountTreeOptions,\n type WoodBridgeFixtureContext,\n type WoodBridgeFixtureInput,\n type WoodBridgeRecordedCall,\n type WoodBridgeRecordedEvent,\n type WoodBrowserExpect,\n type WoodBrowserHarness,\n type WoodBrowserHarnessConfig,\n type WoodBrowserPageContext,\n type WoodViewport,\n} from './browser.js';\nexport { TraceCapture } from '../tracing/index.js';\nexport type {\n TraceCaptureOptions,\n TraceDispatchResult,\n TraceEvent,\n TraceInput,\n TraceWaitOptions,\n} from '../tracing/index.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mCAAoC;AACpC,uCAIO;AACP,gCAAwD;AACxD,2BAAqD;AACrD,kCAIO;AACP,qBAqBO;AACP,qBAA6B;","names":[]}
|
package/dist/testing/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { createTestContainer } from "./create_test_container.js";
|
|
2
2
|
import {
|
|
3
3
|
createControllerHarness
|
|
4
|
-
} from "./create_controller_harness";
|
|
4
|
+
} from "./create_controller_harness.js";
|
|
5
5
|
import { createTestRouter } from "./create_test_router.js";
|
|
6
6
|
import { mockElectron, getElectronMockFactory } from "./mock_electron.js";
|
|
7
7
|
import {
|
|
8
8
|
createRouterBridge,
|
|
9
9
|
RouterBridgeEvents
|
|
10
|
-
} from "./create_router_bridge";
|
|
10
|
+
} from "./create_router_bridge.js";
|
|
11
11
|
import {
|
|
12
12
|
browser,
|
|
13
13
|
createBrowserBridgeFixture
|
|
14
|
-
} from "./browser";
|
|
14
|
+
} from "./browser.js";
|
|
15
15
|
import { TraceCapture } from "../tracing/index.js";
|
|
16
16
|
export {
|
|
17
17
|
RouterBridgeEvents,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/testing/index.ts"],"sourcesContent":["export { createTestContainer } from './create_test_container.js';\nexport {\n createControllerHarness,\n type ControllerHarnessResult,\n type CreateControllerHarnessOptions,\n} from './create_controller_harness';\nexport { createTestRouter, type TestRouterResult } from './create_test_router.js';\nexport { mockElectron, getElectronMockFactory } from './mock_electron.js';\nexport {\n createRouterBridge,\n RouterBridgeEvents,\n type RouterBridgeResult,\n} from './create_router_bridge';\nexport {\n browser,\n createBrowserBridgeFixture,\n type MountedWoodBridge,\n type MountedWoodComponent,\n type MountedWoodNavigation,\n type MountedWoodRoute,\n type MountedWoodSurface,\n type MountedWoodTree,\n type MountComponentOptions,\n type MountRouteOptions,\n type MountTreeOptions,\n type WoodBridgeFixtureContext,\n type WoodBridgeFixtureInput,\n type WoodBridgeRecordedCall,\n type WoodBridgeRecordedEvent,\n type WoodBrowserExpect,\n type WoodBrowserHarness,\n type WoodBrowserHarnessConfig,\n type WoodBrowserPageContext,\n type WoodViewport,\n} from './browser';\nexport { TraceCapture } from '../tracing/index.js';\nexport type {\n TraceCaptureOptions,\n TraceDispatchResult,\n TraceEvent,\n TraceInput,\n TraceWaitOptions,\n} from '../tracing/index.js';\n"],"mappings":"AAAA,SAAS,2BAA2B;AACpC;AAAA,EACE;AAAA,OAGK;AACP,SAAS,wBAA+C;AACxD,SAAS,cAAc,8BAA8B;AACrD;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OAmBK;AACP,SAAS,oBAAoB;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/testing/index.ts"],"sourcesContent":["export { createTestContainer } from './create_test_container.js';\nexport {\n createControllerHarness,\n type ControllerHarnessResult,\n type CreateControllerHarnessOptions,\n} from './create_controller_harness.js';\nexport { createTestRouter, type TestRouterResult } from './create_test_router.js';\nexport { mockElectron, getElectronMockFactory } from './mock_electron.js';\nexport {\n createRouterBridge,\n RouterBridgeEvents,\n type RouterBridgeResult,\n} from './create_router_bridge.js';\nexport {\n browser,\n createBrowserBridgeFixture,\n type MountedWoodBridge,\n type MountedWoodComponent,\n type MountedWoodNavigation,\n type MountedWoodRoute,\n type MountedWoodSurface,\n type MountedWoodTree,\n type MountComponentOptions,\n type MountRouteOptions,\n type MountTreeOptions,\n type WoodBridgeFixtureContext,\n type WoodBridgeFixtureInput,\n type WoodBridgeRecordedCall,\n type WoodBridgeRecordedEvent,\n type WoodBrowserExpect,\n type WoodBrowserHarness,\n type WoodBrowserHarnessConfig,\n type WoodBrowserPageContext,\n type WoodViewport,\n} from './browser.js';\nexport { TraceCapture } from '../tracing/index.js';\nexport type {\n TraceCaptureOptions,\n TraceDispatchResult,\n TraceEvent,\n TraceInput,\n TraceWaitOptions,\n} from '../tracing/index.js';\n"],"mappings":"AAAA,SAAS,2BAA2B;AACpC;AAAA,EACE;AAAA,OAGK;AACP,SAAS,wBAA+C;AACxD,SAAS,cAAc,8BAA8B;AACrD;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OAmBK;AACP,SAAS,oBAAoB;","names":[]}
|
|
@@ -22,69 +22,89 @@ __export(mock_electron_exports, {
|
|
|
22
22
|
mockElectron: () => mockElectron
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(mock_electron_exports);
|
|
25
|
-
|
|
25
|
+
function createMockFunction(implementation) {
|
|
26
|
+
let currentImplementation = implementation ?? (() => void 0);
|
|
27
|
+
const mock = ((...args) => {
|
|
28
|
+
mock.calls.push(args);
|
|
29
|
+
return currentImplementation(...args);
|
|
30
|
+
});
|
|
31
|
+
mock.calls = [];
|
|
32
|
+
mock.mockImplementation = (nextImplementation) => {
|
|
33
|
+
currentImplementation = nextImplementation;
|
|
34
|
+
return mock;
|
|
35
|
+
};
|
|
36
|
+
mock.mockResolvedValue = (value) => {
|
|
37
|
+
currentImplementation = () => Promise.resolve(value);
|
|
38
|
+
return mock;
|
|
39
|
+
};
|
|
40
|
+
mock.mockReturnValue = (value) => {
|
|
41
|
+
currentImplementation = () => value;
|
|
42
|
+
return mock;
|
|
43
|
+
};
|
|
44
|
+
return mock;
|
|
45
|
+
}
|
|
26
46
|
function mockElectron() {
|
|
27
47
|
const mocks = {
|
|
28
48
|
ipcMain: {
|
|
29
|
-
handle:
|
|
30
|
-
removeHandler:
|
|
31
|
-
on:
|
|
49
|
+
handle: createMockFunction(),
|
|
50
|
+
removeHandler: createMockFunction(),
|
|
51
|
+
on: createMockFunction()
|
|
32
52
|
},
|
|
33
53
|
ipcRenderer: {
|
|
34
|
-
invoke:
|
|
35
|
-
send:
|
|
36
|
-
on:
|
|
37
|
-
removeListener:
|
|
54
|
+
invoke: createMockFunction().mockResolvedValue(void 0),
|
|
55
|
+
send: createMockFunction(),
|
|
56
|
+
on: createMockFunction(),
|
|
57
|
+
removeListener: createMockFunction()
|
|
38
58
|
},
|
|
39
|
-
BrowserWindow:
|
|
40
|
-
loadURL:
|
|
41
|
-
loadFile:
|
|
59
|
+
BrowserWindow: createMockFunction().mockImplementation(() => ({
|
|
60
|
+
loadURL: createMockFunction().mockResolvedValue(void 0),
|
|
61
|
+
loadFile: createMockFunction().mockResolvedValue(void 0),
|
|
42
62
|
webContents: {
|
|
43
|
-
send:
|
|
44
|
-
reload:
|
|
45
|
-
on:
|
|
63
|
+
send: createMockFunction(),
|
|
64
|
+
reload: createMockFunction(),
|
|
65
|
+
on: createMockFunction()
|
|
46
66
|
},
|
|
47
|
-
on:
|
|
48
|
-
once:
|
|
49
|
-
close:
|
|
50
|
-
focus:
|
|
51
|
-
show:
|
|
52
|
-
destroy:
|
|
53
|
-
isDestroyed:
|
|
67
|
+
on: createMockFunction(),
|
|
68
|
+
once: createMockFunction(),
|
|
69
|
+
close: createMockFunction(),
|
|
70
|
+
focus: createMockFunction(),
|
|
71
|
+
show: createMockFunction(),
|
|
72
|
+
destroy: createMockFunction(),
|
|
73
|
+
isDestroyed: createMockFunction().mockReturnValue(false)
|
|
54
74
|
})),
|
|
55
75
|
app: {
|
|
56
|
-
getPath:
|
|
57
|
-
on:
|
|
58
|
-
once:
|
|
59
|
-
whenReady:
|
|
76
|
+
getPath: createMockFunction((name) => `/mock/${name}`),
|
|
77
|
+
on: createMockFunction(),
|
|
78
|
+
once: createMockFunction(),
|
|
79
|
+
whenReady: createMockFunction().mockResolvedValue(void 0),
|
|
60
80
|
isPackaged: false,
|
|
61
|
-
quit:
|
|
81
|
+
quit: createMockFunction()
|
|
62
82
|
},
|
|
63
83
|
dialog: {
|
|
64
|
-
showOpenDialog:
|
|
65
|
-
showSaveDialog:
|
|
66
|
-
showMessageBox:
|
|
84
|
+
showOpenDialog: createMockFunction().mockResolvedValue({ filePaths: [], canceled: false }),
|
|
85
|
+
showSaveDialog: createMockFunction().mockResolvedValue({ filePath: "", canceled: false }),
|
|
86
|
+
showMessageBox: createMockFunction().mockResolvedValue({ response: 0 })
|
|
67
87
|
},
|
|
68
88
|
shell: {
|
|
69
|
-
openExternal:
|
|
70
|
-
openPath:
|
|
89
|
+
openExternal: createMockFunction().mockResolvedValue(void 0),
|
|
90
|
+
openPath: createMockFunction().mockResolvedValue("")
|
|
71
91
|
},
|
|
72
92
|
safeStorage: {
|
|
73
|
-
encryptString:
|
|
74
|
-
decryptString:
|
|
75
|
-
isEncryptionAvailable:
|
|
93
|
+
encryptString: createMockFunction().mockReturnValue(Buffer.from("")),
|
|
94
|
+
decryptString: createMockFunction().mockReturnValue(""),
|
|
95
|
+
isEncryptionAvailable: createMockFunction().mockReturnValue(true)
|
|
76
96
|
},
|
|
77
97
|
nativeTheme: {
|
|
78
98
|
shouldUseDarkColors: false,
|
|
79
|
-
on:
|
|
99
|
+
on: createMockFunction()
|
|
80
100
|
},
|
|
81
101
|
globalShortcut: {
|
|
82
|
-
register:
|
|
83
|
-
unregister:
|
|
84
|
-
unregisterAll:
|
|
102
|
+
register: createMockFunction().mockReturnValue(true),
|
|
103
|
+
unregister: createMockFunction(),
|
|
104
|
+
unregisterAll: createMockFunction()
|
|
85
105
|
},
|
|
86
106
|
contextBridge: {
|
|
87
|
-
exposeInMainWorld:
|
|
107
|
+
exposeInMainWorld: createMockFunction()
|
|
88
108
|
}
|
|
89
109
|
};
|
|
90
110
|
return mocks;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/testing/mock_electron.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../src/testing/mock_electron.ts"],"sourcesContent":["type MockFunction = ((...args: any[]) => any) & {\n calls: any[][];\n mockImplementation: (implementation: (...args: any[]) => any) => MockFunction;\n mockResolvedValue: (value: any) => MockFunction;\n mockReturnValue: (value: any) => MockFunction;\n};\n\nfunction createMockFunction(implementation?: (...args: any[]) => any): MockFunction {\n let currentImplementation = implementation ?? (() => undefined);\n const mock = ((...args: any[]) => {\n mock.calls.push(args);\n return currentImplementation(...args);\n }) as MockFunction;\n mock.calls = [];\n mock.mockImplementation = (nextImplementation: (...args: any[]) => any) => {\n currentImplementation = nextImplementation;\n return mock;\n };\n mock.mockResolvedValue = (value: any) => {\n currentImplementation = () => Promise.resolve(value);\n return mock;\n };\n mock.mockReturnValue = (value: any) => {\n currentImplementation = () => value;\n return mock;\n };\n return mock;\n}\n\n/**\n * Comprehensive Electron mock for tests.\n * Call this in your test setup or beforeAll.\n */\nexport function mockElectron(): Record<string, any> {\n // This returns the mock object for use with a test runner's module mock factory.\n const mocks = {\n ipcMain: {\n handle: createMockFunction(),\n removeHandler: createMockFunction(),\n on: createMockFunction(),\n },\n ipcRenderer: {\n invoke: createMockFunction().mockResolvedValue(undefined),\n send: createMockFunction(),\n on: createMockFunction(),\n removeListener: createMockFunction(),\n },\n BrowserWindow: createMockFunction().mockImplementation(() => ({\n loadURL: createMockFunction().mockResolvedValue(undefined),\n loadFile: createMockFunction().mockResolvedValue(undefined),\n webContents: {\n send: createMockFunction(),\n reload: createMockFunction(),\n on: createMockFunction(),\n },\n on: createMockFunction(),\n once: createMockFunction(),\n close: createMockFunction(),\n focus: createMockFunction(),\n show: createMockFunction(),\n destroy: createMockFunction(),\n isDestroyed: createMockFunction().mockReturnValue(false),\n })),\n app: {\n getPath: createMockFunction((name: string) => `/mock/${name}`),\n on: createMockFunction(),\n once: createMockFunction(),\n whenReady: createMockFunction().mockResolvedValue(undefined),\n isPackaged: false,\n quit: createMockFunction(),\n },\n dialog: {\n showOpenDialog: createMockFunction().mockResolvedValue({ filePaths: [], canceled: false }),\n showSaveDialog: createMockFunction().mockResolvedValue({ filePath: '', canceled: false }),\n showMessageBox: createMockFunction().mockResolvedValue({ response: 0 }),\n },\n shell: {\n openExternal: createMockFunction().mockResolvedValue(undefined),\n openPath: createMockFunction().mockResolvedValue(''),\n },\n safeStorage: {\n encryptString: createMockFunction().mockReturnValue(Buffer.from('')),\n decryptString: createMockFunction().mockReturnValue(''),\n isEncryptionAvailable: createMockFunction().mockReturnValue(true),\n },\n nativeTheme: {\n shouldUseDarkColors: false,\n on: createMockFunction(),\n },\n globalShortcut: {\n register: createMockFunction().mockReturnValue(true),\n unregister: createMockFunction(),\n unregisterAll: createMockFunction(),\n },\n contextBridge: {\n exposeInMainWorld: createMockFunction(),\n },\n };\n\n return mocks;\n}\n\n/**\n * Get a module mock factory for Electron.\n * Usage: vi.mock('electron', () => getElectronMockFactory())\n */\nexport function getElectronMockFactory(): Record<string, any> {\n return mockElectron();\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Comprehensive Electron mock for
|
|
2
|
+
* Comprehensive Electron mock for tests.
|
|
3
3
|
* Call this in your test setup or beforeAll.
|
|
4
4
|
*/
|
|
5
5
|
declare function mockElectron(): Record<string, any>;
|
|
6
6
|
/**
|
|
7
|
-
* Get
|
|
7
|
+
* Get a module mock factory for Electron.
|
|
8
8
|
* Usage: vi.mock('electron', () => getElectronMockFactory())
|
|
9
9
|
*/
|
|
10
10
|
declare function getElectronMockFactory(): Record<string, any>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Comprehensive Electron mock for
|
|
2
|
+
* Comprehensive Electron mock for tests.
|
|
3
3
|
* Call this in your test setup or beforeAll.
|
|
4
4
|
*/
|
|
5
5
|
declare function mockElectron(): Record<string, any>;
|
|
6
6
|
/**
|
|
7
|
-
* Get
|
|
7
|
+
* Get a module mock factory for Electron.
|
|
8
8
|
* Usage: vi.mock('electron', () => getElectronMockFactory())
|
|
9
9
|
*/
|
|
10
10
|
declare function getElectronMockFactory(): Record<string, any>;
|
|
@@ -1,66 +1,86 @@
|
|
|
1
|
-
|
|
1
|
+
function createMockFunction(implementation) {
|
|
2
|
+
let currentImplementation = implementation ?? (() => void 0);
|
|
3
|
+
const mock = ((...args) => {
|
|
4
|
+
mock.calls.push(args);
|
|
5
|
+
return currentImplementation(...args);
|
|
6
|
+
});
|
|
7
|
+
mock.calls = [];
|
|
8
|
+
mock.mockImplementation = (nextImplementation) => {
|
|
9
|
+
currentImplementation = nextImplementation;
|
|
10
|
+
return mock;
|
|
11
|
+
};
|
|
12
|
+
mock.mockResolvedValue = (value) => {
|
|
13
|
+
currentImplementation = () => Promise.resolve(value);
|
|
14
|
+
return mock;
|
|
15
|
+
};
|
|
16
|
+
mock.mockReturnValue = (value) => {
|
|
17
|
+
currentImplementation = () => value;
|
|
18
|
+
return mock;
|
|
19
|
+
};
|
|
20
|
+
return mock;
|
|
21
|
+
}
|
|
2
22
|
function mockElectron() {
|
|
3
23
|
const mocks = {
|
|
4
24
|
ipcMain: {
|
|
5
|
-
handle:
|
|
6
|
-
removeHandler:
|
|
7
|
-
on:
|
|
25
|
+
handle: createMockFunction(),
|
|
26
|
+
removeHandler: createMockFunction(),
|
|
27
|
+
on: createMockFunction()
|
|
8
28
|
},
|
|
9
29
|
ipcRenderer: {
|
|
10
|
-
invoke:
|
|
11
|
-
send:
|
|
12
|
-
on:
|
|
13
|
-
removeListener:
|
|
30
|
+
invoke: createMockFunction().mockResolvedValue(void 0),
|
|
31
|
+
send: createMockFunction(),
|
|
32
|
+
on: createMockFunction(),
|
|
33
|
+
removeListener: createMockFunction()
|
|
14
34
|
},
|
|
15
|
-
BrowserWindow:
|
|
16
|
-
loadURL:
|
|
17
|
-
loadFile:
|
|
35
|
+
BrowserWindow: createMockFunction().mockImplementation(() => ({
|
|
36
|
+
loadURL: createMockFunction().mockResolvedValue(void 0),
|
|
37
|
+
loadFile: createMockFunction().mockResolvedValue(void 0),
|
|
18
38
|
webContents: {
|
|
19
|
-
send:
|
|
20
|
-
reload:
|
|
21
|
-
on:
|
|
39
|
+
send: createMockFunction(),
|
|
40
|
+
reload: createMockFunction(),
|
|
41
|
+
on: createMockFunction()
|
|
22
42
|
},
|
|
23
|
-
on:
|
|
24
|
-
once:
|
|
25
|
-
close:
|
|
26
|
-
focus:
|
|
27
|
-
show:
|
|
28
|
-
destroy:
|
|
29
|
-
isDestroyed:
|
|
43
|
+
on: createMockFunction(),
|
|
44
|
+
once: createMockFunction(),
|
|
45
|
+
close: createMockFunction(),
|
|
46
|
+
focus: createMockFunction(),
|
|
47
|
+
show: createMockFunction(),
|
|
48
|
+
destroy: createMockFunction(),
|
|
49
|
+
isDestroyed: createMockFunction().mockReturnValue(false)
|
|
30
50
|
})),
|
|
31
51
|
app: {
|
|
32
|
-
getPath:
|
|
33
|
-
on:
|
|
34
|
-
once:
|
|
35
|
-
whenReady:
|
|
52
|
+
getPath: createMockFunction((name) => `/mock/${name}`),
|
|
53
|
+
on: createMockFunction(),
|
|
54
|
+
once: createMockFunction(),
|
|
55
|
+
whenReady: createMockFunction().mockResolvedValue(void 0),
|
|
36
56
|
isPackaged: false,
|
|
37
|
-
quit:
|
|
57
|
+
quit: createMockFunction()
|
|
38
58
|
},
|
|
39
59
|
dialog: {
|
|
40
|
-
showOpenDialog:
|
|
41
|
-
showSaveDialog:
|
|
42
|
-
showMessageBox:
|
|
60
|
+
showOpenDialog: createMockFunction().mockResolvedValue({ filePaths: [], canceled: false }),
|
|
61
|
+
showSaveDialog: createMockFunction().mockResolvedValue({ filePath: "", canceled: false }),
|
|
62
|
+
showMessageBox: createMockFunction().mockResolvedValue({ response: 0 })
|
|
43
63
|
},
|
|
44
64
|
shell: {
|
|
45
|
-
openExternal:
|
|
46
|
-
openPath:
|
|
65
|
+
openExternal: createMockFunction().mockResolvedValue(void 0),
|
|
66
|
+
openPath: createMockFunction().mockResolvedValue("")
|
|
47
67
|
},
|
|
48
68
|
safeStorage: {
|
|
49
|
-
encryptString:
|
|
50
|
-
decryptString:
|
|
51
|
-
isEncryptionAvailable:
|
|
69
|
+
encryptString: createMockFunction().mockReturnValue(Buffer.from("")),
|
|
70
|
+
decryptString: createMockFunction().mockReturnValue(""),
|
|
71
|
+
isEncryptionAvailable: createMockFunction().mockReturnValue(true)
|
|
52
72
|
},
|
|
53
73
|
nativeTheme: {
|
|
54
74
|
shouldUseDarkColors: false,
|
|
55
|
-
on:
|
|
75
|
+
on: createMockFunction()
|
|
56
76
|
},
|
|
57
77
|
globalShortcut: {
|
|
58
|
-
register:
|
|
59
|
-
unregister:
|
|
60
|
-
unregisterAll:
|
|
78
|
+
register: createMockFunction().mockReturnValue(true),
|
|
79
|
+
unregister: createMockFunction(),
|
|
80
|
+
unregisterAll: createMockFunction()
|
|
61
81
|
},
|
|
62
82
|
contextBridge: {
|
|
63
|
-
exposeInMainWorld:
|
|
83
|
+
exposeInMainWorld: createMockFunction()
|
|
64
84
|
}
|
|
65
85
|
};
|
|
66
86
|
return mocks;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/testing/mock_electron.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../src/testing/mock_electron.ts"],"sourcesContent":["type MockFunction = ((...args: any[]) => any) & {\n calls: any[][];\n mockImplementation: (implementation: (...args: any[]) => any) => MockFunction;\n mockResolvedValue: (value: any) => MockFunction;\n mockReturnValue: (value: any) => MockFunction;\n};\n\nfunction createMockFunction(implementation?: (...args: any[]) => any): MockFunction {\n let currentImplementation = implementation ?? (() => undefined);\n const mock = ((...args: any[]) => {\n mock.calls.push(args);\n return currentImplementation(...args);\n }) as MockFunction;\n mock.calls = [];\n mock.mockImplementation = (nextImplementation: (...args: any[]) => any) => {\n currentImplementation = nextImplementation;\n return mock;\n };\n mock.mockResolvedValue = (value: any) => {\n currentImplementation = () => Promise.resolve(value);\n return mock;\n };\n mock.mockReturnValue = (value: any) => {\n currentImplementation = () => value;\n return mock;\n };\n return mock;\n}\n\n/**\n * Comprehensive Electron mock for tests.\n * Call this in your test setup or beforeAll.\n */\nexport function mockElectron(): Record<string, any> {\n // This returns the mock object for use with a test runner's module mock factory.\n const mocks = {\n ipcMain: {\n handle: createMockFunction(),\n removeHandler: createMockFunction(),\n on: createMockFunction(),\n },\n ipcRenderer: {\n invoke: createMockFunction().mockResolvedValue(undefined),\n send: createMockFunction(),\n on: createMockFunction(),\n removeListener: createMockFunction(),\n },\n BrowserWindow: createMockFunction().mockImplementation(() => ({\n loadURL: createMockFunction().mockResolvedValue(undefined),\n loadFile: createMockFunction().mockResolvedValue(undefined),\n webContents: {\n send: createMockFunction(),\n reload: createMockFunction(),\n on: createMockFunction(),\n },\n on: createMockFunction(),\n once: createMockFunction(),\n close: createMockFunction(),\n focus: createMockFunction(),\n show: createMockFunction(),\n destroy: createMockFunction(),\n isDestroyed: createMockFunction().mockReturnValue(false),\n })),\n app: {\n getPath: createMockFunction((name: string) => `/mock/${name}`),\n on: createMockFunction(),\n once: createMockFunction(),\n whenReady: createMockFunction().mockResolvedValue(undefined),\n isPackaged: false,\n quit: createMockFunction(),\n },\n dialog: {\n showOpenDialog: createMockFunction().mockResolvedValue({ filePaths: [], canceled: false }),\n showSaveDialog: createMockFunction().mockResolvedValue({ filePath: '', canceled: false }),\n showMessageBox: createMockFunction().mockResolvedValue({ response: 0 }),\n },\n shell: {\n openExternal: createMockFunction().mockResolvedValue(undefined),\n openPath: createMockFunction().mockResolvedValue(''),\n },\n safeStorage: {\n encryptString: createMockFunction().mockReturnValue(Buffer.from('')),\n decryptString: createMockFunction().mockReturnValue(''),\n isEncryptionAvailable: createMockFunction().mockReturnValue(true),\n },\n nativeTheme: {\n shouldUseDarkColors: false,\n on: createMockFunction(),\n },\n globalShortcut: {\n register: createMockFunction().mockReturnValue(true),\n unregister: createMockFunction(),\n unregisterAll: createMockFunction(),\n },\n contextBridge: {\n exposeInMainWorld: createMockFunction(),\n },\n };\n\n return mocks;\n}\n\n/**\n * Get a module mock factory for Electron.\n * Usage: vi.mock('electron', () => getElectronMockFactory())\n */\nexport function getElectronMockFactory(): Record<string, any> {\n return mockElectron();\n}\n"],"mappings":"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","names":[]}
|
package/dist/types/views.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/types/views.ts"],"sourcesContent":["/** Types for views YAML (frontend page/layout definitions) */\n\n/** Fully resolved view definition after YAML parsing */\nexport interface ViewDef {\n windowName: string;\n pageName: string;\n viewPath: string;\n layouts: string[];\n layoutControllers?: Array<string | undefined>;\n middleware?: string[];\n parameters?: ParameterDef[];\n controller?: string;\n}\n\n/** OpenAPI-style parameter definition for view routes */\nexport interface ParameterDef {\n name: string;\n in: string;\n required?: boolean;\n schema?: Record<string, unknown>;\n}\n\n/** Raw views YAML document before resolution */\nexport interface RawViewsDocument {\n view?: Record<string, RawViewEntry>;\n}\n\n/** A simple view entry using dot-path keys */\nexport interface RawViewEntry {\n view: string;\n layout?: RawLayoutConfig;\n middleware?: string[];\n controller?: string;\n}\n\nexport type RawLayoutConfig = RawLayoutEntry[] | RawLayoutEntry | RawLayoutGroupEntry;\n\nexport type RawLayoutEntry = string | RawLayoutObjectEntry;\n\nexport interface RawLayoutObjectEntry {\n path?: string;\n view?: string;\n layout?: string;\n controller?: string;\n}\n\nexport interface RawLayoutGroupEntry {\n controller?: string;\n views: RawLayoutEntry[];\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/types/views.ts"],"sourcesContent":["/** Types for views YAML (frontend page/layout definitions) */\n\n/** Fully resolved view definition after YAML parsing */\nexport interface ViewDef {\n windowName: string;\n pageName: string;\n viewPath: string;\n layouts: string[];\n layoutControllers?: Array<string | undefined>;\n layoutPreserve?: boolean[];\n middleware?: string[];\n parameters?: ParameterDef[];\n controller?: string;\n}\n\n/** OpenAPI-style parameter definition for view routes */\nexport interface ParameterDef {\n name: string;\n in: string;\n required?: boolean;\n schema?: Record<string, unknown>;\n}\n\n/** Raw views YAML document before resolution */\nexport interface RawViewsDocument {\n view?: Record<string, RawViewEntry>;\n}\n\n/** A simple view entry using dot-path keys */\nexport interface RawViewEntry {\n view: string;\n layout?: RawLayoutConfig;\n middleware?: string[];\n controller?: string;\n}\n\nexport type RawLayoutConfig = RawLayoutEntry[] | RawLayoutEntry | RawLayoutGroupEntry;\n\nexport type RawLayoutEntry = string | RawLayoutObjectEntry;\n\nexport interface RawLayoutObjectEntry {\n path?: string;\n view?: string;\n layout?: string;\n controller?: string;\n preserve?: boolean;\n}\n\nexport interface RawLayoutGroupEntry {\n controller?: string;\n preserve?: boolean;\n views: RawLayoutEntry[];\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
package/dist/types/views.d.cts
CHANGED
|
@@ -6,6 +6,7 @@ interface ViewDef {
|
|
|
6
6
|
viewPath: string;
|
|
7
7
|
layouts: string[];
|
|
8
8
|
layoutControllers?: Array<string | undefined>;
|
|
9
|
+
layoutPreserve?: boolean[];
|
|
9
10
|
middleware?: string[];
|
|
10
11
|
parameters?: ParameterDef[];
|
|
11
12
|
controller?: string;
|
|
@@ -35,9 +36,11 @@ interface RawLayoutObjectEntry {
|
|
|
35
36
|
view?: string;
|
|
36
37
|
layout?: string;
|
|
37
38
|
controller?: string;
|
|
39
|
+
preserve?: boolean;
|
|
38
40
|
}
|
|
39
41
|
interface RawLayoutGroupEntry {
|
|
40
42
|
controller?: string;
|
|
43
|
+
preserve?: boolean;
|
|
41
44
|
views: RawLayoutEntry[];
|
|
42
45
|
}
|
|
43
46
|
|
package/dist/types/views.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ interface ViewDef {
|
|
|
6
6
|
viewPath: string;
|
|
7
7
|
layouts: string[];
|
|
8
8
|
layoutControllers?: Array<string | undefined>;
|
|
9
|
+
layoutPreserve?: boolean[];
|
|
9
10
|
middleware?: string[];
|
|
10
11
|
parameters?: ParameterDef[];
|
|
11
12
|
controller?: string;
|
|
@@ -35,9 +36,11 @@ interface RawLayoutObjectEntry {
|
|
|
35
36
|
view?: string;
|
|
36
37
|
layout?: string;
|
|
37
38
|
controller?: string;
|
|
39
|
+
preserve?: boolean;
|
|
38
40
|
}
|
|
39
41
|
interface RawLayoutGroupEntry {
|
|
40
42
|
controller?: string;
|
|
43
|
+
preserve?: boolean;
|
|
41
44
|
views: RawLayoutEntry[];
|
|
42
45
|
}
|
|
43
46
|
|