@noego/wood 0.6.2 → 0.7.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.
Files changed (242) hide show
  1. package/README.md +7 -0
  2. package/dist/browser-test-setup.cjs +29 -0
  3. package/dist/browser-test-setup.cjs.map +1 -0
  4. package/dist/browser-test-setup.d.cts +8 -0
  5. package/dist/browser-test-setup.d.ts +8 -0
  6. package/dist/browser-test-setup.js +9 -0
  7. package/dist/browser-test-setup.js.map +1 -0
  8. package/dist/client/global_polyfill.d.cts +1 -0
  9. package/dist/client/global_polyfill.d.ts +1 -0
  10. package/dist/client/index.cjs +7 -0
  11. package/dist/client/index.cjs.map +1 -1
  12. package/dist/client/index.d.cts +7 -4
  13. package/dist/client/index.d.ts +7 -4
  14. package/dist/client/index.js +6 -1
  15. package/dist/client/index.js.map +1 -1
  16. package/dist/codegen/renderer_app_generator.cjs +97 -24
  17. package/dist/codegen/renderer_app_generator.cjs.map +1 -1
  18. package/dist/codegen/renderer_app_generator.js +97 -24
  19. package/dist/codegen/renderer_app_generator.js.map +1 -1
  20. package/dist/codegen/type_generator.cjs +9 -0
  21. package/dist/codegen/type_generator.cjs.map +1 -1
  22. package/dist/codegen/type_generator.js +9 -0
  23. package/dist/codegen/type_generator.js.map +1 -1
  24. package/dist/config/config_parser.cjs +10 -0
  25. package/dist/config/config_parser.cjs.map +1 -1
  26. package/dist/config/config_parser.js +10 -0
  27. package/dist/config/config_parser.js.map +1 -1
  28. package/dist/fetch.cjs +38 -0
  29. package/dist/fetch.cjs.map +1 -0
  30. package/dist/fetch.d.cts +7 -0
  31. package/dist/fetch.d.ts +7 -0
  32. package/dist/fetch.js +12 -0
  33. package/dist/fetch.js.map +1 -0
  34. package/dist/frontend/frontend_page.cjs +3 -3
  35. package/dist/frontend/frontend_page.cjs.map +1 -1
  36. package/dist/frontend/frontend_page.d.cts +1 -1
  37. package/dist/frontend/frontend_page.d.ts +1 -1
  38. package/dist/frontend/frontend_page.js +3 -3
  39. package/dist/frontend/frontend_page.js.map +1 -1
  40. package/dist/frontend/frontend_surface.cjs +31 -17
  41. package/dist/frontend/frontend_surface.cjs.map +1 -1
  42. package/dist/frontend/frontend_surface.d.cts +12 -2
  43. package/dist/frontend/frontend_surface.d.ts +12 -2
  44. package/dist/frontend/frontend_surface.js +37 -17
  45. package/dist/frontend/frontend_surface.js.map +1 -1
  46. package/dist/frontend/index.d.cts +2 -0
  47. package/dist/frontend/index.d.ts +2 -0
  48. package/dist/index.cjs +5 -0
  49. package/dist/index.cjs.map +1 -1
  50. package/dist/index.d.cts +25 -0
  51. package/dist/index.d.ts +25 -0
  52. package/dist/index.js +3 -0
  53. package/dist/index.js.map +1 -1
  54. package/dist/loader/index.cjs +19 -2
  55. package/dist/loader/index.cjs.map +1 -1
  56. package/dist/loader/index.d.cts +1 -0
  57. package/dist/loader/index.d.ts +1 -0
  58. package/dist/loader/index.js +19 -1
  59. package/dist/loader/index.js.map +1 -1
  60. package/dist/loader/loader_orchestration.cjs +82 -0
  61. package/dist/loader/loader_orchestration.cjs.map +1 -0
  62. package/dist/loader/loader_orchestration.d.cts +66 -0
  63. package/dist/loader/loader_orchestration.d.ts +66 -0
  64. package/dist/loader/loader_orchestration.js +51 -0
  65. package/dist/loader/loader_orchestration.js.map +1 -0
  66. package/dist/loader/loader_runner.cjs +46 -41
  67. package/dist/loader/loader_runner.cjs.map +1 -1
  68. package/dist/loader/loader_runner.d.cts +12 -6
  69. package/dist/loader/loader_runner.d.ts +12 -6
  70. package/dist/loader/loader_runner.js +50 -41
  71. package/dist/loader/loader_runner.js.map +1 -1
  72. package/dist/native_browser.types-BY2daUOS.d.ts +189 -0
  73. package/dist/native_browser.types-vWXtE4rM.d.cts +189 -0
  74. package/dist/navigation/index.cjs +15 -2
  75. package/dist/navigation/index.cjs.map +1 -1
  76. package/dist/navigation/index.d.cts +2 -0
  77. package/dist/navigation/index.d.ts +2 -0
  78. package/dist/navigation/index.js +8 -1
  79. package/dist/navigation/index.js.map +1 -1
  80. package/dist/runtime/get_container.cjs +2 -0
  81. package/dist/runtime/get_container.cjs.map +1 -1
  82. package/dist/runtime/get_container.js +2 -0
  83. package/dist/runtime/get_container.js.map +1 -1
  84. package/dist/runtime/index.cjs +5 -0
  85. package/dist/runtime/index.cjs.map +1 -1
  86. package/dist/runtime/index.d.cts +2 -0
  87. package/dist/runtime/index.d.ts +2 -0
  88. package/dist/runtime/index.js +3 -0
  89. package/dist/runtime/index.js.map +1 -1
  90. package/dist/runtime/runtime_capabilities.cjs +35 -0
  91. package/dist/runtime/runtime_capabilities.cjs.map +1 -0
  92. package/dist/runtime/runtime_capabilities.d.cts +6 -0
  93. package/dist/runtime/runtime_capabilities.d.ts +6 -0
  94. package/dist/runtime/runtime_capabilities.js +11 -0
  95. package/dist/runtime/runtime_capabilities.js.map +1 -0
  96. package/dist/runtime/runtime_module.cjs +2 -0
  97. package/dist/runtime/runtime_module.cjs.map +1 -1
  98. package/dist/runtime/runtime_module.js +2 -0
  99. package/dist/runtime/runtime_module.js.map +1 -1
  100. package/dist/test-wood.cjs +150 -0
  101. package/dist/test-wood.cjs.map +1 -0
  102. package/dist/test-wood.d.cts +62 -0
  103. package/dist/test-wood.d.ts +62 -0
  104. package/dist/test-wood.js +115 -0
  105. package/dist/test-wood.js.map +1 -0
  106. package/dist/testing/browser.cjs +92 -163
  107. package/dist/testing/browser.cjs.map +1 -1
  108. package/dist/testing/browser.d.cts +14 -13
  109. package/dist/testing/browser.d.ts +14 -13
  110. package/dist/testing/browser.js +88 -162
  111. package/dist/testing/browser.js.map +1 -1
  112. package/dist/testing/create_controller_harness.d.cts +2 -1
  113. package/dist/testing/create_controller_harness.d.ts +2 -1
  114. package/dist/testing/create_router_bridge.cjs +19 -15
  115. package/dist/testing/create_router_bridge.cjs.map +1 -1
  116. package/dist/testing/create_router_bridge.d.cts +8 -1
  117. package/dist/testing/create_router_bridge.d.ts +8 -1
  118. package/dist/testing/create_router_bridge.js +18 -15
  119. package/dist/testing/create_router_bridge.js.map +1 -1
  120. package/dist/testing/index.cjs +12 -4
  121. package/dist/testing/index.cjs.map +1 -1
  122. package/dist/testing/index.d.cts +11 -5
  123. package/dist/testing/index.d.ts +11 -5
  124. package/dist/testing/index.js +9 -3
  125. package/dist/testing/index.js.map +1 -1
  126. package/dist/testing/native_browser/browser_pool.cjs +31 -0
  127. package/dist/testing/native_browser/browser_pool.cjs.map +1 -0
  128. package/dist/testing/native_browser/browser_pool.d.cts +1 -0
  129. package/dist/testing/native_browser/browser_pool.d.ts +1 -0
  130. package/dist/testing/native_browser/browser_pool.js +6 -0
  131. package/dist/testing/native_browser/browser_pool.js.map +1 -0
  132. package/dist/testing/native_browser/happy_dom_tab.cjs +107 -0
  133. package/dist/testing/native_browser/happy_dom_tab.cjs.map +1 -0
  134. package/dist/testing/native_browser/happy_dom_tab.d.cts +35 -0
  135. package/dist/testing/native_browser/happy_dom_tab.d.ts +35 -0
  136. package/dist/testing/native_browser/happy_dom_tab.js +73 -0
  137. package/dist/testing/native_browser/happy_dom_tab.js.map +1 -0
  138. package/dist/testing/native_browser/happy_dom_transfer.cjs +29 -0
  139. package/dist/testing/native_browser/happy_dom_transfer.cjs.map +1 -0
  140. package/dist/testing/native_browser/happy_dom_transfer.d.cts +1 -0
  141. package/dist/testing/native_browser/happy_dom_transfer.d.ts +1 -0
  142. package/dist/testing/native_browser/happy_dom_transfer.js +5 -0
  143. package/dist/testing/native_browser/happy_dom_transfer.js.map +1 -0
  144. package/dist/testing/native_browser/host_transport.cjs +89 -0
  145. package/dist/testing/native_browser/host_transport.cjs.map +1 -0
  146. package/dist/testing/native_browser/host_transport.d.cts +44 -0
  147. package/dist/testing/native_browser/host_transport.d.ts +44 -0
  148. package/dist/testing/native_browser/host_transport.js +65 -0
  149. package/dist/testing/native_browser/host_transport.js.map +1 -0
  150. package/dist/testing/native_browser/native_browser.types.cjs +17 -0
  151. package/dist/testing/native_browser/native_browser.types.cjs.map +1 -0
  152. package/dist/testing/native_browser/native_browser.types.d.cts +31 -0
  153. package/dist/testing/native_browser/native_browser.types.d.ts +31 -0
  154. package/dist/testing/native_browser/native_browser.types.js +1 -0
  155. package/dist/testing/native_browser/native_browser.types.js.map +1 -0
  156. package/dist/testing/native_browser/native_browser_environment.cjs +143 -0
  157. package/dist/testing/native_browser/native_browser_environment.cjs.map +1 -0
  158. package/dist/testing/native_browser/native_browser_environment.d.cts +36 -0
  159. package/dist/testing/native_browser/native_browser_environment.d.ts +36 -0
  160. package/dist/testing/native_browser/native_browser_environment.js +109 -0
  161. package/dist/testing/native_browser/native_browser_environment.js.map +1 -0
  162. package/dist/testing/native_browser/native_browser_lifecycle.cjs +31 -0
  163. package/dist/testing/native_browser/native_browser_lifecycle.cjs.map +1 -0
  164. package/dist/testing/native_browser/native_browser_lifecycle.d.cts +1 -0
  165. package/dist/testing/native_browser/native_browser_lifecycle.d.ts +1 -0
  166. package/dist/testing/native_browser/native_browser_lifecycle.js +6 -0
  167. package/dist/testing/native_browser/native_browser_lifecycle.js.map +1 -0
  168. package/dist/testing/native_browser/playwright_tab.cjs +124 -0
  169. package/dist/testing/native_browser/playwright_tab.cjs.map +1 -0
  170. package/dist/testing/native_browser/playwright_tab.d.cts +35 -0
  171. package/dist/testing/native_browser/playwright_tab.d.ts +35 -0
  172. package/dist/testing/native_browser/playwright_tab.js +100 -0
  173. package/dist/testing/native_browser/playwright_tab.js.map +1 -0
  174. package/dist/testing/native_browser/renderer_compilation.cjs +149 -0
  175. package/dist/testing/native_browser/renderer_compilation.cjs.map +1 -0
  176. package/dist/testing/native_browser/renderer_compilation.d.cts +35 -0
  177. package/dist/testing/native_browser/renderer_compilation.d.ts +35 -0
  178. package/dist/testing/native_browser/renderer_compilation.js +115 -0
  179. package/dist/testing/native_browser/renderer_compilation.js.map +1 -0
  180. package/dist/testing/native_browser/renderer_entry.cjs +148 -0
  181. package/dist/testing/native_browser/renderer_entry.cjs.map +1 -0
  182. package/dist/testing/native_browser/renderer_entry.d.cts +13 -0
  183. package/dist/testing/native_browser/renderer_entry.d.ts +13 -0
  184. package/dist/testing/native_browser/renderer_entry.js +114 -0
  185. package/dist/testing/native_browser/renderer_entry.js.map +1 -0
  186. package/dist/testing/registration_only_root.cjs +61 -5
  187. package/dist/testing/registration_only_root.cjs.map +1 -1
  188. package/dist/testing/registration_only_root.d.cts +25 -4
  189. package/dist/testing/registration_only_root.d.ts +25 -4
  190. package/dist/testing/registration_only_root.js +60 -5
  191. package/dist/testing/registration_only_root.js.map +1 -1
  192. package/dist/testing/runner_importer.cjs +75 -0
  193. package/dist/testing/runner_importer.cjs.map +1 -0
  194. package/dist/testing/runner_importer.d.cts +8 -0
  195. package/dist/testing/runner_importer.d.ts +8 -0
  196. package/dist/testing/runner_importer.js +41 -0
  197. package/dist/testing/runner_importer.js.map +1 -0
  198. package/dist/testing/test_wood_config.cjs +387 -272
  199. package/dist/testing/test_wood_config.cjs.map +1 -1
  200. package/dist/testing/test_wood_config.d.cts +18 -123
  201. package/dist/testing/test_wood_config.d.ts +18 -123
  202. package/dist/testing/test_wood_config.js +396 -270
  203. package/dist/testing/test_wood_config.js.map +1 -1
  204. package/dist/testing/wood_config_source.cjs +12 -0
  205. package/dist/testing/wood_config_source.cjs.map +1 -1
  206. package/dist/testing/wood_config_source.d.cts +10 -0
  207. package/dist/testing/wood_config_source.d.ts +10 -0
  208. package/dist/testing/wood_config_source.js +12 -0
  209. package/dist/testing/wood_config_source.js.map +1 -1
  210. package/dist/testing/wood_env_renderer.cjs +28 -3
  211. package/dist/testing/wood_env_renderer.cjs.map +1 -1
  212. package/dist/testing/wood_env_renderer.d.cts +12 -1
  213. package/dist/testing/wood_env_renderer.d.ts +12 -1
  214. package/dist/testing/wood_env_renderer.js +28 -3
  215. package/dist/testing/wood_env_renderer.js.map +1 -1
  216. package/dist/testing/wood_lazy_runtime.cjs +109 -0
  217. package/dist/testing/wood_lazy_runtime.cjs.map +1 -0
  218. package/dist/testing/wood_lazy_runtime.d.cts +36 -0
  219. package/dist/testing/wood_lazy_runtime.d.ts +36 -0
  220. package/dist/testing/wood_lazy_runtime.js +84 -0
  221. package/dist/testing/wood_lazy_runtime.js.map +1 -0
  222. package/dist/testing/wood_test_selection.cjs +34 -55
  223. package/dist/testing/wood_test_selection.cjs.map +1 -1
  224. package/dist/testing/wood_test_selection.d.cts +18 -24
  225. package/dist/testing/wood_test_selection.d.ts +18 -24
  226. package/dist/testing/wood_test_selection.js +30 -54
  227. package/dist/testing/wood_test_selection.js.map +1 -1
  228. package/dist/testing-api.cjs +17 -0
  229. package/dist/testing-api.cjs.map +1 -0
  230. package/dist/testing-api.d.cts +18 -0
  231. package/dist/testing-api.d.ts +18 -0
  232. package/dist/testing-api.js +1 -0
  233. package/dist/testing-api.js.map +1 -0
  234. package/dist/types/config.cjs.map +1 -1
  235. package/dist/types/config.d.cts +4 -0
  236. package/dist/types/config.d.ts +4 -0
  237. package/docs/native-browser-testing.md +164 -0
  238. package/package.json +31 -5
  239. package/src/components/NavigationShell.browser.test.ts +10 -10
  240. package/src/components/NavigationShell.cleanup.browser.test.ts +57 -0
  241. package/src/components/NavigationShell.scopes.browser.test.ts +5 -5
  242. package/src/components/NavigationShell.svelte +50 -24
@@ -18,77 +18,56 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var wood_test_selection_exports = {};
20
20
  __export(wood_test_selection_exports, {
21
+ DECLARED_OWNERS: () => DECLARED_OWNERS,
22
+ hasRendererTier: () => hasRendererTier,
21
23
  resolveSelection: () => resolveSelection,
22
- selectCatalog: () => selectCatalog,
23
- selectOperations: () => selectOperations
24
+ selectOperations: () => selectOperations,
25
+ selectRendererCatalog: () => selectRendererCatalog,
26
+ selectViews: () => selectViews
24
27
  });
25
28
  module.exports = __toCommonJS(wood_test_selection_exports);
29
+ var import_testing = require("@noego/testing");
26
30
  var import_page_catalog = require("../frontend/page_catalog.js");
27
31
  var import_test_wood = require("./test_wood.cjs");
28
- const DOM_MODES = ["happy-dom", "chromium"];
29
- function isMainSelection(value) {
30
- if (value === true) return true;
31
- if (!value || typeof value !== "object") return false;
32
- const candidate = value;
33
- const hasOperation = typeof candidate.operation === "string" && candidate.operation.length > 0;
34
- const hasModule = typeof candidate.module === "string" && candidate.module.length > 0;
35
- return hasOperation !== hasModule;
36
- }
37
- function isPagesSelection(value) {
38
- if (value === true) return true;
39
- return Array.isArray(value) && value.length > 0 && value.every((entry) => typeof entry === "string" && entry.length > 0);
32
+ function hasRendererTier(selection) {
33
+ return selection.renderer !== null;
40
34
  }
35
+ const DECLARED_OWNERS = Object.freeze(["main", "renderer"]);
41
36
  function resolveSelection(selection) {
42
- if (!selection || typeof selection !== "object") {
43
- throw new import_test_wood.TestWoodError("select() requires { main }, { pages }, or both (plus optional dom)");
44
- }
45
- const { main, pages, dom } = selection;
46
- if (main !== void 0 && !isMainSelection(main)) {
47
- throw new import_test_wood.TestWoodError("select({ main }) must be true, { operation: string } or { module: string }");
48
- }
49
- if (pages !== void 0 && !isPagesSelection(pages)) {
50
- throw new import_test_wood.TestWoodError("select({ pages }) must be true or a non-empty list of page identities");
51
- }
52
- if (dom !== void 0 && !DOM_MODES.includes(dom)) {
53
- throw new import_test_wood.TestWoodError(`select({ dom }) must be one of: ${DOM_MODES.join(", ")}`);
54
- }
55
- if (dom !== void 0 && pages === void 0) {
56
- throw new import_test_wood.TestWoodError("select({ dom }) requires { pages }: a component needs a page to mount");
37
+ if (!selection || typeof selection !== "object" || Array.isArray(selection)) {
38
+ throw new import_test_wood.TestWoodError("select() requires { main } and/or { renderer }");
57
39
  }
58
- if (main === void 0 && pages === void 0) {
59
- throw new import_test_wood.TestWoodError("select() built nothing: add { main } and/or { pages }");
40
+ const normalized = (0, import_testing.normalizeTestSelection)(selection, DECLARED_OWNERS);
41
+ if (normalized.main === void 0 && normalized.renderer === void 0) {
42
+ throw new import_test_wood.TestWoodError("select() built nothing: add { main } and/or { renderer }");
60
43
  }
61
- return { main: main ?? true, pages: pages ?? null, dom: dom ?? null };
62
- }
63
- function operationIdentities(operations) {
64
- if (!operations.size) return "the config defines no operations";
65
- return `available operations:
66
- ${[...operations.keys()].join("\n ")}`;
44
+ return Object.freeze({
45
+ main: normalized.main ?? null,
46
+ renderer: normalized.renderer ?? null
47
+ });
67
48
  }
68
49
  function selectOperations(all, main) {
69
- if (main === true) return new Map(all);
70
- if ("module" in main) {
71
- const matched = new Map([...all].filter(([, operation]) => operation.module === main.module));
72
- if (matched.size) return matched;
73
- const modules = [...new Set([...all.values()].map((operation) => operation.module).filter(Boolean))];
74
- throw new import_test_wood.TestWoodError(
75
- `unknown module "${main.module}"; ` + (modules.length ? `available modules: ${modules.join(", ")}` : "the config defines no modules")
76
- );
77
- }
78
- const match = all.get(main.operation);
79
- if (!match) {
80
- throw new import_test_wood.TestWoodError(`no operation matches "${main.operation}"; ${operationIdentities(all)}`);
81
- }
82
- return /* @__PURE__ */ new Map([[main.operation, match]]);
50
+ if (main === null) return /* @__PURE__ */ new Map();
51
+ const source = [...all].map(([path, operation]) => ({ path, module: operation.module, operation }));
52
+ return new Map((0, import_testing.selectSourceEntries)(source, main, { owner: "main", native: true }).map((e) => [e.path, e.operation]));
83
53
  }
84
- function selectCatalog(views, pages) {
54
+ function selectViews(views, renderer) {
85
55
  const catalog = new import_page_catalog.PageCatalog(views);
86
- return pages === true ? catalog : catalog.select({ pages });
56
+ const source = catalog.all().map((view) => ({ path: (0, import_page_catalog.pageIdentity)(view), module: view.windowName, view }));
57
+ const windows = [...new Set(source.map((entry) => entry.module))];
58
+ const selected = (0, import_testing.selectSourceEntries)(source, renderer, { owner: "renderer", native: true, modules: windows });
59
+ return new import_page_catalog.PageCatalog(selected.map((entry) => entry.view));
60
+ }
61
+ function selectRendererCatalog(views, selection) {
62
+ return selection.renderer !== null ? selectViews(views(), selection.renderer) : null;
87
63
  }
88
64
  // Annotate the CommonJS export names for ESM import in node:
89
65
  0 && (module.exports = {
66
+ DECLARED_OWNERS,
67
+ hasRendererTier,
90
68
  resolveSelection,
91
- selectCatalog,
92
- selectOperations
69
+ selectOperations,
70
+ selectRendererCatalog,
71
+ selectViews
93
72
  });
94
73
  //# sourceMappingURL=wood_test_selection.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/testing/wood_test_selection.ts"],"sourcesContent":["/**\n * `testWood(configPath).select({...})` — one declarative object says which\n * tiers exist and how they are observed:\n *\n * main true | { operation } | { module } the router + real controllers\n * pages true | [identity, ...] the renderer page catalog\n * dom 'happy-dom' | 'chromium' the page's real component\n *\n * A key that is absent is not built. `pages` implies `main: true`; `dom`\n * requires `pages`. Nothing opens at build — tests drive `open()`.\n */\nimport type { OperationDef, ViewDef } from '../types/index.cjs';\nimport { PageCatalog } from '../frontend/page_catalog.js';\nimport { TestWoodError } from './test_wood.cjs';\n\nexport type WoodMainSelection = true | { operation: string } | { module: string };\nexport type WoodDomMode = 'happy-dom' | 'chromium';\n\nexport interface WoodTestSelection {\n main?: WoodMainSelection;\n pages?: true | string[];\n dom?: WoodDomMode;\n}\n\nexport interface ResolvedWoodSelection {\n readonly main: WoodMainSelection;\n readonly pages: true | string[] | null;\n readonly dom: WoodDomMode | null;\n}\n\nconst DOM_MODES: readonly WoodDomMode[] = ['happy-dom', 'chromium'];\n\nfunction isMainSelection(value: unknown): value is WoodMainSelection {\n if (value === true) return true;\n if (!value || typeof value !== 'object') return false;\n const candidate = value as { operation?: unknown; module?: unknown };\n const hasOperation = typeof candidate.operation === 'string' && candidate.operation.length > 0;\n const hasModule = typeof candidate.module === 'string' && candidate.module.length > 0;\n return hasOperation !== hasModule;\n}\n\nfunction isPagesSelection(value: unknown): value is true | string[] {\n if (value === true) return true;\n return Array.isArray(value)\n && value.length > 0\n && value.every((entry) => typeof entry === 'string' && entry.length > 0);\n}\n\nexport function resolveSelection(selection: WoodTestSelection | null): ResolvedWoodSelection {\n if (!selection || typeof selection !== 'object') {\n throw new TestWoodError('select() requires { main }, { pages }, or both (plus optional dom)');\n }\n const { main, pages, dom } = selection;\n if (main !== undefined && !isMainSelection(main)) {\n throw new TestWoodError('select({ main }) must be true, { operation: string } or { module: string }');\n }\n if (pages !== undefined && !isPagesSelection(pages)) {\n throw new TestWoodError('select({ pages }) must be true or a non-empty list of page identities');\n }\n if (dom !== undefined && !DOM_MODES.includes(dom)) {\n throw new TestWoodError(`select({ dom }) must be one of: ${DOM_MODES.join(', ')}`);\n }\n if (dom !== undefined && pages === undefined) {\n throw new TestWoodError('select({ dom }) requires { pages }: a component needs a page to mount');\n }\n if (main === undefined && pages === undefined) {\n throw new TestWoodError('select() built nothing: add { main } and/or { pages }');\n }\n return { main: main ?? true, pages: pages ?? null, dom: dom ?? null };\n}\n\nfunction operationIdentities(operations: Map<string, OperationDef>): string {\n if (!operations.size) return 'the config defines no operations';\n return `available operations:\\n ${[...operations.keys()].join('\\n ')}`;\n}\n\n/** Narrow the production operations to the selected main aperture. */\nexport function selectOperations(\n all: Map<string, OperationDef>,\n main: WoodMainSelection,\n): Map<string, OperationDef> {\n if (main === true) return new Map(all);\n if ('module' in main) {\n const matched = new Map([...all].filter(([, operation]) => operation.module === main.module));\n if (matched.size) return matched;\n const modules = [...new Set([...all.values()].map((operation) => operation.module).filter(Boolean))];\n throw new TestWoodError(\n `unknown module \"${main.module}\"; ` +\n (modules.length ? `available modules: ${modules.join(', ')}` : 'the config defines no modules'),\n );\n }\n const match = all.get(main.operation);\n if (!match) {\n throw new TestWoodError(`no operation matches \"${main.operation}\"; ${operationIdentities(all)}`);\n }\n return new Map([[main.operation, match]]);\n}\n\n/** The renderer aperture: every production page, or exactly the named ones. */\nexport function selectCatalog(views: ViewDef[], pages: true | string[]): PageCatalog {\n const catalog = new PageCatalog(views);\n return pages === true ? catalog : catalog.select({ pages });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA,0BAA4B;AAC5B,uBAA8B;AAiB9B,MAAM,YAAoC,CAAC,aAAa,UAAU;AAElE,SAAS,gBAAgB,OAA4C;AACnE,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,YAAY;AAClB,QAAM,eAAe,OAAO,UAAU,cAAc,YAAY,UAAU,UAAU,SAAS;AAC7F,QAAM,YAAY,OAAO,UAAU,WAAW,YAAY,UAAU,OAAO,SAAS;AACpF,SAAO,iBAAiB;AAC1B;AAEA,SAAS,iBAAiB,OAA0C;AAClE,MAAI,UAAU,KAAM,QAAO;AAC3B,SAAO,MAAM,QAAQ,KAAK,KACrB,MAAM,SAAS,KACf,MAAM,MAAM,CAAC,UAAU,OAAO,UAAU,YAAY,MAAM,SAAS,CAAC;AAC3E;AAEO,SAAS,iBAAiB,WAA4D;AAC3F,MAAI,CAAC,aAAa,OAAO,cAAc,UAAU;AAC/C,UAAM,IAAI,+BAAc,oEAAoE;AAAA,EAC9F;AACA,QAAM,EAAE,MAAM,OAAO,IAAI,IAAI;AAC7B,MAAI,SAAS,UAAa,CAAC,gBAAgB,IAAI,GAAG;AAChD,UAAM,IAAI,+BAAc,4EAA4E;AAAA,EACtG;AACA,MAAI,UAAU,UAAa,CAAC,iBAAiB,KAAK,GAAG;AACnD,UAAM,IAAI,+BAAc,uEAAuE;AAAA,EACjG;AACA,MAAI,QAAQ,UAAa,CAAC,UAAU,SAAS,GAAG,GAAG;AACjD,UAAM,IAAI,+BAAc,mCAAmC,UAAU,KAAK,IAAI,CAAC,EAAE;AAAA,EACnF;AACA,MAAI,QAAQ,UAAa,UAAU,QAAW;AAC5C,UAAM,IAAI,+BAAc,uEAAuE;AAAA,EACjG;AACA,MAAI,SAAS,UAAa,UAAU,QAAW;AAC7C,UAAM,IAAI,+BAAc,uDAAuD;AAAA,EACjF;AACA,SAAO,EAAE,MAAM,QAAQ,MAAM,OAAO,SAAS,MAAM,KAAK,OAAO,KAAK;AACtE;AAEA,SAAS,oBAAoB,YAA+C;AAC1E,MAAI,CAAC,WAAW,KAAM,QAAO;AAC7B,SAAO;AAAA,IAA4B,CAAC,GAAG,WAAW,KAAK,CAAC,EAAE,KAAK,MAAM,CAAC;AACxE;AAGO,SAAS,iBACd,KACA,MAC2B;AAC3B,MAAI,SAAS,KAAM,QAAO,IAAI,IAAI,GAAG;AACrC,MAAI,YAAY,MAAM;AACpB,UAAM,UAAU,IAAI,IAAI,CAAC,GAAG,GAAG,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS,MAAM,UAAU,WAAW,KAAK,MAAM,CAAC;AAC5F,QAAI,QAAQ,KAAM,QAAO;AACzB,UAAM,UAAU,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,EAAE,IAAI,CAAC,cAAc,UAAU,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC;AACnG,UAAM,IAAI;AAAA,MACR,mBAAmB,KAAK,MAAM,SAC7B,QAAQ,SAAS,sBAAsB,QAAQ,KAAK,IAAI,CAAC,KAAK;AAAA,IACjE;AAAA,EACF;AACA,QAAM,QAAQ,IAAI,IAAI,KAAK,SAAS;AACpC,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,+BAAc,yBAAyB,KAAK,SAAS,MAAM,oBAAoB,GAAG,CAAC,EAAE;AAAA,EACjG;AACA,SAAO,oBAAI,IAAI,CAAC,CAAC,KAAK,WAAW,KAAK,CAAC,CAAC;AAC1C;AAGO,SAAS,cAAc,OAAkB,OAAqC;AACnF,QAAM,UAAU,IAAI,gCAAY,KAAK;AACrC,SAAO,UAAU,OAAO,UAAU,QAAQ,OAAO,EAAE,MAAM,CAAC;AAC5D;","names":[]}
1
+ {"version":3,"sources":["../../src/testing/wood_test_selection.ts"],"sourcesContent":["/**\n * Canonical `testWood(configPath).select({...})` source aperture.\n *\n * `main` and `renderer` use the shared @noego/testing OwnerSelection contract:\n * `{ module }`, `{ path }`, or `{}`. An omitted owner is omitted; selecting a\n * renderer never widens main. Browser/DOM hosting is selected separately with\n * `.browser()` / `.browser('happy_dom')`.\n */\nimport type { OperationDef, ViewDef } from '../types/index.cjs';\nimport { normalizeTestSelection, selectSourceEntries, type OwnerSelection } from '@noego/testing';\nimport { PageCatalog, pageIdentity } from '../frontend/page_catalog.js';\nimport { TestWoodError } from './test_wood.cjs';\n\nexport type WoodMainSelection = OwnerSelection;\nexport type WoodRendererSelection = OwnerSelection;\nexport type WoodDomMode = never;\n\nexport interface WoodTestSelection {\n main?: WoodMainSelection;\n renderer?: WoodRendererSelection;\n}\n\nexport interface ResolvedWoodSelection {\n readonly main: WoodMainSelection | null;\n readonly renderer: WoodRendererSelection | null;\n}\n\nexport function hasRendererTier(selection: ResolvedWoodSelection): boolean {\n return selection.renderer !== null;\n}\n\nexport const DECLARED_OWNERS: readonly ('main' | 'renderer')[] = Object.freeze(['main', 'renderer']);\n\nexport function resolveSelection(selection: WoodTestSelection | null): ResolvedWoodSelection {\n if (!selection || typeof selection !== 'object' || Array.isArray(selection)) {\n throw new TestWoodError('select() requires { main } and/or { renderer }');\n }\n const normalized = normalizeTestSelection(selection, DECLARED_OWNERS);\n if (normalized.main === undefined && normalized.renderer === undefined) {\n throw new TestWoodError('select() built nothing: add { main } and/or { renderer }');\n }\n return Object.freeze({\n main: normalized.main ?? null,\n renderer: normalized.renderer ?? null,\n });\n}\n\nexport function selectOperations(\n all: Map<string, OperationDef>,\n main: WoodMainSelection | null,\n): Map<string, OperationDef> {\n if (main === null) return new Map();\n const source = [...all].map(([path, operation]) => ({ path, module: operation.module, operation }));\n return new Map(selectSourceEntries(source, main, { owner: 'main', native: true }).map(e => [e.path, e.operation]));\n}\n\nexport function selectViews(views: ViewDef[], renderer: WoodRendererSelection): PageCatalog {\n const catalog = new PageCatalog(views);\n const source = catalog.all().map((view) => ({ path: pageIdentity(view), module: view.windowName, view }));\n const windows = [...new Set(source.map((entry) => entry.module))];\n const selected = selectSourceEntries(source, renderer, { owner: 'renderer', native: true, modules: windows });\n return new PageCatalog(selected.map((entry) => entry.view));\n}\n\nexport function selectRendererCatalog(views: () => ViewDef[], selection: ResolvedWoodSelection): PageCatalog | null {\n return selection.renderer !== null ? selectViews(views(), selection.renderer) : null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,qBAAiF;AACjF,0BAA0C;AAC1C,uBAA8B;AAgBvB,SAAS,gBAAgB,WAA2C;AACzE,SAAO,UAAU,aAAa;AAChC;AAEO,MAAM,kBAAoD,OAAO,OAAO,CAAC,QAAQ,UAAU,CAAC;AAE5F,SAAS,iBAAiB,WAA4D;AAC3F,MAAI,CAAC,aAAa,OAAO,cAAc,YAAY,MAAM,QAAQ,SAAS,GAAG;AAC3E,UAAM,IAAI,+BAAc,gDAAgD;AAAA,EAC1E;AACA,QAAM,iBAAa,uCAAuB,WAAW,eAAe;AACpE,MAAI,WAAW,SAAS,UAAa,WAAW,aAAa,QAAW;AACtE,UAAM,IAAI,+BAAc,0DAA0D;AAAA,EACpF;AACA,SAAO,OAAO,OAAO;AAAA,IACnB,MAAM,WAAW,QAAQ;AAAA,IACzB,UAAU,WAAW,YAAY;AAAA,EACnC,CAAC;AACH;AAEO,SAAS,iBACd,KACA,MAC2B;AAC3B,MAAI,SAAS,KAAM,QAAO,oBAAI,IAAI;AAClC,QAAM,SAAS,CAAC,GAAG,GAAG,EAAE,IAAI,CAAC,CAAC,MAAM,SAAS,OAAO,EAAE,MAAM,QAAQ,UAAU,QAAQ,UAAU,EAAE;AAClG,SAAO,IAAI,QAAI,oCAAoB,QAAQ,MAAM,EAAE,OAAO,QAAQ,QAAQ,KAAK,CAAC,EAAE,IAAI,OAAK,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;AACnH;AAEO,SAAS,YAAY,OAAkB,UAA8C;AAC1F,QAAM,UAAU,IAAI,gCAAY,KAAK;AACrC,QAAM,SAAS,QAAQ,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,UAAM,kCAAa,IAAI,GAAG,QAAQ,KAAK,YAAY,KAAK,EAAE;AACxG,QAAM,UAAU,CAAC,GAAG,IAAI,IAAI,OAAO,IAAI,CAAC,UAAU,MAAM,MAAM,CAAC,CAAC;AAChE,QAAM,eAAW,oCAAoB,QAAQ,UAAU,EAAE,OAAO,YAAY,QAAQ,MAAM,SAAS,QAAQ,CAAC;AAC5G,SAAO,IAAI,gCAAY,SAAS,IAAI,CAAC,UAAU,MAAM,IAAI,CAAC;AAC5D;AAEO,SAAS,sBAAsB,OAAwB,WAAsD;AAClH,SAAO,UAAU,aAAa,OAAO,YAAY,MAAM,GAAG,UAAU,QAAQ,IAAI;AAClF;","names":[]}
@@ -1,39 +1,33 @@
1
1
  import { OperationDef } from '../types/operations.cjs';
2
2
  import { ViewDef } from '../types/views.cjs';
3
+ import { OwnerSelection } from '@noego/testing';
3
4
  import { PageCatalog } from '../frontend/page_catalog.cjs';
4
5
 
5
6
  /**
6
- * `testWood(configPath).select({...})` — one declarative object says which
7
- * tiers exist and how they are observed:
7
+ * Canonical `testWood(configPath).select({...})` source aperture.
8
8
  *
9
- * main true | { operation } | { module } the router + real controllers
10
- * pages true | [identity, ...] the renderer page catalog
11
- * dom 'happy-dom' | 'chromium' the page's real component
12
- *
13
- * A key that is absent is not built. `pages` implies `main: true`; `dom`
14
- * requires `pages`. Nothing opens at build — tests drive `open()`.
9
+ * `main` and `renderer` use the shared @noego/testing OwnerSelection contract:
10
+ * `{ module }`, `{ path }`, or `{}`. An omitted owner is omitted; selecting a
11
+ * renderer never widens main. Browser/DOM hosting is selected separately with
12
+ * `.browser()` / `.browser('happy_dom')`.
15
13
  */
16
14
 
17
- type WoodMainSelection = true | {
18
- operation: string;
19
- } | {
20
- module: string;
21
- };
22
- type WoodDomMode = 'happy-dom' | 'chromium';
15
+ type WoodMainSelection = OwnerSelection;
16
+ type WoodRendererSelection = OwnerSelection;
17
+ type WoodDomMode = never;
23
18
  interface WoodTestSelection {
24
19
  main?: WoodMainSelection;
25
- pages?: true | string[];
26
- dom?: WoodDomMode;
20
+ renderer?: WoodRendererSelection;
27
21
  }
28
22
  interface ResolvedWoodSelection {
29
- readonly main: WoodMainSelection;
30
- readonly pages: true | string[] | null;
31
- readonly dom: WoodDomMode | null;
23
+ readonly main: WoodMainSelection | null;
24
+ readonly renderer: WoodRendererSelection | null;
32
25
  }
26
+ declare function hasRendererTier(selection: ResolvedWoodSelection): boolean;
27
+ declare const DECLARED_OWNERS: readonly ('main' | 'renderer')[];
33
28
  declare function resolveSelection(selection: WoodTestSelection | null): ResolvedWoodSelection;
34
- /** Narrow the production operations to the selected main aperture. */
35
- declare function selectOperations(all: Map<string, OperationDef>, main: WoodMainSelection): Map<string, OperationDef>;
36
- /** The renderer aperture: every production page, or exactly the named ones. */
37
- declare function selectCatalog(views: ViewDef[], pages: true | string[]): PageCatalog;
29
+ declare function selectOperations(all: Map<string, OperationDef>, main: WoodMainSelection | null): Map<string, OperationDef>;
30
+ declare function selectViews(views: ViewDef[], renderer: WoodRendererSelection): PageCatalog;
31
+ declare function selectRendererCatalog(views: () => ViewDef[], selection: ResolvedWoodSelection): PageCatalog | null;
38
32
 
39
- export { type ResolvedWoodSelection, type WoodDomMode, type WoodMainSelection, type WoodTestSelection, resolveSelection, selectCatalog, selectOperations };
33
+ export { DECLARED_OWNERS, type ResolvedWoodSelection, type WoodDomMode, type WoodMainSelection, type WoodRendererSelection, type WoodTestSelection, hasRendererTier, resolveSelection, selectOperations, selectRendererCatalog, selectViews };
@@ -1,39 +1,33 @@
1
1
  import { OperationDef } from '../types/operations.js';
2
2
  import { ViewDef } from '../types/views.js';
3
+ import { OwnerSelection } from '@noego/testing';
3
4
  import { PageCatalog } from '../frontend/page_catalog.js';
4
5
 
5
6
  /**
6
- * `testWood(configPath).select({...})` — one declarative object says which
7
- * tiers exist and how they are observed:
7
+ * Canonical `testWood(configPath).select({...})` source aperture.
8
8
  *
9
- * main true | { operation } | { module } the router + real controllers
10
- * pages true | [identity, ...] the renderer page catalog
11
- * dom 'happy-dom' | 'chromium' the page's real component
12
- *
13
- * A key that is absent is not built. `pages` implies `main: true`; `dom`
14
- * requires `pages`. Nothing opens at build — tests drive `open()`.
9
+ * `main` and `renderer` use the shared @noego/testing OwnerSelection contract:
10
+ * `{ module }`, `{ path }`, or `{}`. An omitted owner is omitted; selecting a
11
+ * renderer never widens main. Browser/DOM hosting is selected separately with
12
+ * `.browser()` / `.browser('happy_dom')`.
15
13
  */
16
14
 
17
- type WoodMainSelection = true | {
18
- operation: string;
19
- } | {
20
- module: string;
21
- };
22
- type WoodDomMode = 'happy-dom' | 'chromium';
15
+ type WoodMainSelection = OwnerSelection;
16
+ type WoodRendererSelection = OwnerSelection;
17
+ type WoodDomMode = never;
23
18
  interface WoodTestSelection {
24
19
  main?: WoodMainSelection;
25
- pages?: true | string[];
26
- dom?: WoodDomMode;
20
+ renderer?: WoodRendererSelection;
27
21
  }
28
22
  interface ResolvedWoodSelection {
29
- readonly main: WoodMainSelection;
30
- readonly pages: true | string[] | null;
31
- readonly dom: WoodDomMode | null;
23
+ readonly main: WoodMainSelection | null;
24
+ readonly renderer: WoodRendererSelection | null;
32
25
  }
26
+ declare function hasRendererTier(selection: ResolvedWoodSelection): boolean;
27
+ declare const DECLARED_OWNERS: readonly ('main' | 'renderer')[];
33
28
  declare function resolveSelection(selection: WoodTestSelection | null): ResolvedWoodSelection;
34
- /** Narrow the production operations to the selected main aperture. */
35
- declare function selectOperations(all: Map<string, OperationDef>, main: WoodMainSelection): Map<string, OperationDef>;
36
- /** The renderer aperture: every production page, or exactly the named ones. */
37
- declare function selectCatalog(views: ViewDef[], pages: true | string[]): PageCatalog;
29
+ declare function selectOperations(all: Map<string, OperationDef>, main: WoodMainSelection | null): Map<string, OperationDef>;
30
+ declare function selectViews(views: ViewDef[], renderer: WoodRendererSelection): PageCatalog;
31
+ declare function selectRendererCatalog(views: () => ViewDef[], selection: ResolvedWoodSelection): PageCatalog | null;
38
32
 
39
- export { type ResolvedWoodSelection, type WoodDomMode, type WoodMainSelection, type WoodTestSelection, resolveSelection, selectCatalog, selectOperations };
33
+ export { DECLARED_OWNERS, type ResolvedWoodSelection, type WoodDomMode, type WoodMainSelection, type WoodRendererSelection, type WoodTestSelection, hasRendererTier, resolveSelection, selectOperations, selectRendererCatalog, selectViews };
@@ -1,68 +1,44 @@
1
- import { PageCatalog } from "../frontend/page_catalog.js";
1
+ import { normalizeTestSelection, selectSourceEntries } from "@noego/testing";
2
+ import { PageCatalog, pageIdentity } from "../frontend/page_catalog.js";
2
3
  import { TestWoodError } from "./test_wood.js";
3
- const DOM_MODES = ["happy-dom", "chromium"];
4
- function isMainSelection(value) {
5
- if (value === true) return true;
6
- if (!value || typeof value !== "object") return false;
7
- const candidate = value;
8
- const hasOperation = typeof candidate.operation === "string" && candidate.operation.length > 0;
9
- const hasModule = typeof candidate.module === "string" && candidate.module.length > 0;
10
- return hasOperation !== hasModule;
11
- }
12
- function isPagesSelection(value) {
13
- if (value === true) return true;
14
- return Array.isArray(value) && value.length > 0 && value.every((entry) => typeof entry === "string" && entry.length > 0);
4
+ function hasRendererTier(selection) {
5
+ return selection.renderer !== null;
15
6
  }
7
+ const DECLARED_OWNERS = Object.freeze(["main", "renderer"]);
16
8
  function resolveSelection(selection) {
17
- if (!selection || typeof selection !== "object") {
18
- throw new TestWoodError("select() requires { main }, { pages }, or both (plus optional dom)");
19
- }
20
- const { main, pages, dom } = selection;
21
- if (main !== void 0 && !isMainSelection(main)) {
22
- throw new TestWoodError("select({ main }) must be true, { operation: string } or { module: string }");
23
- }
24
- if (pages !== void 0 && !isPagesSelection(pages)) {
25
- throw new TestWoodError("select({ pages }) must be true or a non-empty list of page identities");
26
- }
27
- if (dom !== void 0 && !DOM_MODES.includes(dom)) {
28
- throw new TestWoodError(`select({ dom }) must be one of: ${DOM_MODES.join(", ")}`);
29
- }
30
- if (dom !== void 0 && pages === void 0) {
31
- throw new TestWoodError("select({ dom }) requires { pages }: a component needs a page to mount");
9
+ if (!selection || typeof selection !== "object" || Array.isArray(selection)) {
10
+ throw new TestWoodError("select() requires { main } and/or { renderer }");
32
11
  }
33
- if (main === void 0 && pages === void 0) {
34
- throw new TestWoodError("select() built nothing: add { main } and/or { pages }");
12
+ const normalized = normalizeTestSelection(selection, DECLARED_OWNERS);
13
+ if (normalized.main === void 0 && normalized.renderer === void 0) {
14
+ throw new TestWoodError("select() built nothing: add { main } and/or { renderer }");
35
15
  }
36
- return { main: main ?? true, pages: pages ?? null, dom: dom ?? null };
37
- }
38
- function operationIdentities(operations) {
39
- if (!operations.size) return "the config defines no operations";
40
- return `available operations:
41
- ${[...operations.keys()].join("\n ")}`;
16
+ return Object.freeze({
17
+ main: normalized.main ?? null,
18
+ renderer: normalized.renderer ?? null
19
+ });
42
20
  }
43
21
  function selectOperations(all, main) {
44
- if (main === true) return new Map(all);
45
- if ("module" in main) {
46
- const matched = new Map([...all].filter(([, operation]) => operation.module === main.module));
47
- if (matched.size) return matched;
48
- const modules = [...new Set([...all.values()].map((operation) => operation.module).filter(Boolean))];
49
- throw new TestWoodError(
50
- `unknown module "${main.module}"; ` + (modules.length ? `available modules: ${modules.join(", ")}` : "the config defines no modules")
51
- );
52
- }
53
- const match = all.get(main.operation);
54
- if (!match) {
55
- throw new TestWoodError(`no operation matches "${main.operation}"; ${operationIdentities(all)}`);
56
- }
57
- return /* @__PURE__ */ new Map([[main.operation, match]]);
22
+ if (main === null) return /* @__PURE__ */ new Map();
23
+ const source = [...all].map(([path, operation]) => ({ path, module: operation.module, operation }));
24
+ return new Map(selectSourceEntries(source, main, { owner: "main", native: true }).map((e) => [e.path, e.operation]));
58
25
  }
59
- function selectCatalog(views, pages) {
26
+ function selectViews(views, renderer) {
60
27
  const catalog = new PageCatalog(views);
61
- return pages === true ? catalog : catalog.select({ pages });
28
+ const source = catalog.all().map((view) => ({ path: pageIdentity(view), module: view.windowName, view }));
29
+ const windows = [...new Set(source.map((entry) => entry.module))];
30
+ const selected = selectSourceEntries(source, renderer, { owner: "renderer", native: true, modules: windows });
31
+ return new PageCatalog(selected.map((entry) => entry.view));
32
+ }
33
+ function selectRendererCatalog(views, selection) {
34
+ return selection.renderer !== null ? selectViews(views(), selection.renderer) : null;
62
35
  }
63
36
  export {
37
+ DECLARED_OWNERS,
38
+ hasRendererTier,
64
39
  resolveSelection,
65
- selectCatalog,
66
- selectOperations
40
+ selectOperations,
41
+ selectRendererCatalog,
42
+ selectViews
67
43
  };
68
44
  //# sourceMappingURL=wood_test_selection.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/testing/wood_test_selection.ts"],"sourcesContent":["/**\n * `testWood(configPath).select({...})` — one declarative object says which\n * tiers exist and how they are observed:\n *\n * main true | { operation } | { module } the router + real controllers\n * pages true | [identity, ...] the renderer page catalog\n * dom 'happy-dom' | 'chromium' the page's real component\n *\n * A key that is absent is not built. `pages` implies `main: true`; `dom`\n * requires `pages`. Nothing opens at build — tests drive `open()`.\n */\nimport type { OperationDef, ViewDef } from '../types/index.js';\nimport { PageCatalog } from '../frontend/page_catalog.js';\nimport { TestWoodError } from './test_wood.js';\n\nexport type WoodMainSelection = true | { operation: string } | { module: string };\nexport type WoodDomMode = 'happy-dom' | 'chromium';\n\nexport interface WoodTestSelection {\n main?: WoodMainSelection;\n pages?: true | string[];\n dom?: WoodDomMode;\n}\n\nexport interface ResolvedWoodSelection {\n readonly main: WoodMainSelection;\n readonly pages: true | string[] | null;\n readonly dom: WoodDomMode | null;\n}\n\nconst DOM_MODES: readonly WoodDomMode[] = ['happy-dom', 'chromium'];\n\nfunction isMainSelection(value: unknown): value is WoodMainSelection {\n if (value === true) return true;\n if (!value || typeof value !== 'object') return false;\n const candidate = value as { operation?: unknown; module?: unknown };\n const hasOperation = typeof candidate.operation === 'string' && candidate.operation.length > 0;\n const hasModule = typeof candidate.module === 'string' && candidate.module.length > 0;\n return hasOperation !== hasModule;\n}\n\nfunction isPagesSelection(value: unknown): value is true | string[] {\n if (value === true) return true;\n return Array.isArray(value)\n && value.length > 0\n && value.every((entry) => typeof entry === 'string' && entry.length > 0);\n}\n\nexport function resolveSelection(selection: WoodTestSelection | null): ResolvedWoodSelection {\n if (!selection || typeof selection !== 'object') {\n throw new TestWoodError('select() requires { main }, { pages }, or both (plus optional dom)');\n }\n const { main, pages, dom } = selection;\n if (main !== undefined && !isMainSelection(main)) {\n throw new TestWoodError('select({ main }) must be true, { operation: string } or { module: string }');\n }\n if (pages !== undefined && !isPagesSelection(pages)) {\n throw new TestWoodError('select({ pages }) must be true or a non-empty list of page identities');\n }\n if (dom !== undefined && !DOM_MODES.includes(dom)) {\n throw new TestWoodError(`select({ dom }) must be one of: ${DOM_MODES.join(', ')}`);\n }\n if (dom !== undefined && pages === undefined) {\n throw new TestWoodError('select({ dom }) requires { pages }: a component needs a page to mount');\n }\n if (main === undefined && pages === undefined) {\n throw new TestWoodError('select() built nothing: add { main } and/or { pages }');\n }\n return { main: main ?? true, pages: pages ?? null, dom: dom ?? null };\n}\n\nfunction operationIdentities(operations: Map<string, OperationDef>): string {\n if (!operations.size) return 'the config defines no operations';\n return `available operations:\\n ${[...operations.keys()].join('\\n ')}`;\n}\n\n/** Narrow the production operations to the selected main aperture. */\nexport function selectOperations(\n all: Map<string, OperationDef>,\n main: WoodMainSelection,\n): Map<string, OperationDef> {\n if (main === true) return new Map(all);\n if ('module' in main) {\n const matched = new Map([...all].filter(([, operation]) => operation.module === main.module));\n if (matched.size) return matched;\n const modules = [...new Set([...all.values()].map((operation) => operation.module).filter(Boolean))];\n throw new TestWoodError(\n `unknown module \"${main.module}\"; ` +\n (modules.length ? `available modules: ${modules.join(', ')}` : 'the config defines no modules'),\n );\n }\n const match = all.get(main.operation);\n if (!match) {\n throw new TestWoodError(`no operation matches \"${main.operation}\"; ${operationIdentities(all)}`);\n }\n return new Map([[main.operation, match]]);\n}\n\n/** The renderer aperture: every production page, or exactly the named ones. */\nexport function selectCatalog(views: ViewDef[], pages: true | string[]): PageCatalog {\n const catalog = new PageCatalog(views);\n return pages === true ? catalog : catalog.select({ pages });\n}\n"],"mappings":"AAYA,SAAS,mBAAmB;AAC5B,SAAS,qBAAqB;AAiB9B,MAAM,YAAoC,CAAC,aAAa,UAAU;AAElE,SAAS,gBAAgB,OAA4C;AACnE,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,YAAY;AAClB,QAAM,eAAe,OAAO,UAAU,cAAc,YAAY,UAAU,UAAU,SAAS;AAC7F,QAAM,YAAY,OAAO,UAAU,WAAW,YAAY,UAAU,OAAO,SAAS;AACpF,SAAO,iBAAiB;AAC1B;AAEA,SAAS,iBAAiB,OAA0C;AAClE,MAAI,UAAU,KAAM,QAAO;AAC3B,SAAO,MAAM,QAAQ,KAAK,KACrB,MAAM,SAAS,KACf,MAAM,MAAM,CAAC,UAAU,OAAO,UAAU,YAAY,MAAM,SAAS,CAAC;AAC3E;AAEO,SAAS,iBAAiB,WAA4D;AAC3F,MAAI,CAAC,aAAa,OAAO,cAAc,UAAU;AAC/C,UAAM,IAAI,cAAc,oEAAoE;AAAA,EAC9F;AACA,QAAM,EAAE,MAAM,OAAO,IAAI,IAAI;AAC7B,MAAI,SAAS,UAAa,CAAC,gBAAgB,IAAI,GAAG;AAChD,UAAM,IAAI,cAAc,4EAA4E;AAAA,EACtG;AACA,MAAI,UAAU,UAAa,CAAC,iBAAiB,KAAK,GAAG;AACnD,UAAM,IAAI,cAAc,uEAAuE;AAAA,EACjG;AACA,MAAI,QAAQ,UAAa,CAAC,UAAU,SAAS,GAAG,GAAG;AACjD,UAAM,IAAI,cAAc,mCAAmC,UAAU,KAAK,IAAI,CAAC,EAAE;AAAA,EACnF;AACA,MAAI,QAAQ,UAAa,UAAU,QAAW;AAC5C,UAAM,IAAI,cAAc,uEAAuE;AAAA,EACjG;AACA,MAAI,SAAS,UAAa,UAAU,QAAW;AAC7C,UAAM,IAAI,cAAc,uDAAuD;AAAA,EACjF;AACA,SAAO,EAAE,MAAM,QAAQ,MAAM,OAAO,SAAS,MAAM,KAAK,OAAO,KAAK;AACtE;AAEA,SAAS,oBAAoB,YAA+C;AAC1E,MAAI,CAAC,WAAW,KAAM,QAAO;AAC7B,SAAO;AAAA,IAA4B,CAAC,GAAG,WAAW,KAAK,CAAC,EAAE,KAAK,MAAM,CAAC;AACxE;AAGO,SAAS,iBACd,KACA,MAC2B;AAC3B,MAAI,SAAS,KAAM,QAAO,IAAI,IAAI,GAAG;AACrC,MAAI,YAAY,MAAM;AACpB,UAAM,UAAU,IAAI,IAAI,CAAC,GAAG,GAAG,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS,MAAM,UAAU,WAAW,KAAK,MAAM,CAAC;AAC5F,QAAI,QAAQ,KAAM,QAAO;AACzB,UAAM,UAAU,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,EAAE,IAAI,CAAC,cAAc,UAAU,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC;AACnG,UAAM,IAAI;AAAA,MACR,mBAAmB,KAAK,MAAM,SAC7B,QAAQ,SAAS,sBAAsB,QAAQ,KAAK,IAAI,CAAC,KAAK;AAAA,IACjE;AAAA,EACF;AACA,QAAM,QAAQ,IAAI,IAAI,KAAK,SAAS;AACpC,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,cAAc,yBAAyB,KAAK,SAAS,MAAM,oBAAoB,GAAG,CAAC,EAAE;AAAA,EACjG;AACA,SAAO,oBAAI,IAAI,CAAC,CAAC,KAAK,WAAW,KAAK,CAAC,CAAC;AAC1C;AAGO,SAAS,cAAc,OAAkB,OAAqC;AACnF,QAAM,UAAU,IAAI,YAAY,KAAK;AACrC,SAAO,UAAU,OAAO,UAAU,QAAQ,OAAO,EAAE,MAAM,CAAC;AAC5D;","names":[]}
1
+ {"version":3,"sources":["../../src/testing/wood_test_selection.ts"],"sourcesContent":["/**\n * Canonical `testWood(configPath).select({...})` source aperture.\n *\n * `main` and `renderer` use the shared @noego/testing OwnerSelection contract:\n * `{ module }`, `{ path }`, or `{}`. An omitted owner is omitted; selecting a\n * renderer never widens main. Browser/DOM hosting is selected separately with\n * `.browser()` / `.browser('happy_dom')`.\n */\nimport type { OperationDef, ViewDef } from '../types/index.js';\nimport { normalizeTestSelection, selectSourceEntries, type OwnerSelection } from '@noego/testing';\nimport { PageCatalog, pageIdentity } from '../frontend/page_catalog.js';\nimport { TestWoodError } from './test_wood.js';\n\nexport type WoodMainSelection = OwnerSelection;\nexport type WoodRendererSelection = OwnerSelection;\nexport type WoodDomMode = never;\n\nexport interface WoodTestSelection {\n main?: WoodMainSelection;\n renderer?: WoodRendererSelection;\n}\n\nexport interface ResolvedWoodSelection {\n readonly main: WoodMainSelection | null;\n readonly renderer: WoodRendererSelection | null;\n}\n\nexport function hasRendererTier(selection: ResolvedWoodSelection): boolean {\n return selection.renderer !== null;\n}\n\nexport const DECLARED_OWNERS: readonly ('main' | 'renderer')[] = Object.freeze(['main', 'renderer']);\n\nexport function resolveSelection(selection: WoodTestSelection | null): ResolvedWoodSelection {\n if (!selection || typeof selection !== 'object' || Array.isArray(selection)) {\n throw new TestWoodError('select() requires { main } and/or { renderer }');\n }\n const normalized = normalizeTestSelection(selection, DECLARED_OWNERS);\n if (normalized.main === undefined && normalized.renderer === undefined) {\n throw new TestWoodError('select() built nothing: add { main } and/or { renderer }');\n }\n return Object.freeze({\n main: normalized.main ?? null,\n renderer: normalized.renderer ?? null,\n });\n}\n\nexport function selectOperations(\n all: Map<string, OperationDef>,\n main: WoodMainSelection | null,\n): Map<string, OperationDef> {\n if (main === null) return new Map();\n const source = [...all].map(([path, operation]) => ({ path, module: operation.module, operation }));\n return new Map(selectSourceEntries(source, main, { owner: 'main', native: true }).map(e => [e.path, e.operation]));\n}\n\nexport function selectViews(views: ViewDef[], renderer: WoodRendererSelection): PageCatalog {\n const catalog = new PageCatalog(views);\n const source = catalog.all().map((view) => ({ path: pageIdentity(view), module: view.windowName, view }));\n const windows = [...new Set(source.map((entry) => entry.module))];\n const selected = selectSourceEntries(source, renderer, { owner: 'renderer', native: true, modules: windows });\n return new PageCatalog(selected.map((entry) => entry.view));\n}\n\nexport function selectRendererCatalog(views: () => ViewDef[], selection: ResolvedWoodSelection): PageCatalog | null {\n return selection.renderer !== null ? selectViews(views(), selection.renderer) : null;\n}\n"],"mappings":"AASA,SAAS,wBAAwB,2BAAgD;AACjF,SAAS,aAAa,oBAAoB;AAC1C,SAAS,qBAAqB;AAgBvB,SAAS,gBAAgB,WAA2C;AACzE,SAAO,UAAU,aAAa;AAChC;AAEO,MAAM,kBAAoD,OAAO,OAAO,CAAC,QAAQ,UAAU,CAAC;AAE5F,SAAS,iBAAiB,WAA4D;AAC3F,MAAI,CAAC,aAAa,OAAO,cAAc,YAAY,MAAM,QAAQ,SAAS,GAAG;AAC3E,UAAM,IAAI,cAAc,gDAAgD;AAAA,EAC1E;AACA,QAAM,aAAa,uBAAuB,WAAW,eAAe;AACpE,MAAI,WAAW,SAAS,UAAa,WAAW,aAAa,QAAW;AACtE,UAAM,IAAI,cAAc,0DAA0D;AAAA,EACpF;AACA,SAAO,OAAO,OAAO;AAAA,IACnB,MAAM,WAAW,QAAQ;AAAA,IACzB,UAAU,WAAW,YAAY;AAAA,EACnC,CAAC;AACH;AAEO,SAAS,iBACd,KACA,MAC2B;AAC3B,MAAI,SAAS,KAAM,QAAO,oBAAI,IAAI;AAClC,QAAM,SAAS,CAAC,GAAG,GAAG,EAAE,IAAI,CAAC,CAAC,MAAM,SAAS,OAAO,EAAE,MAAM,QAAQ,UAAU,QAAQ,UAAU,EAAE;AAClG,SAAO,IAAI,IAAI,oBAAoB,QAAQ,MAAM,EAAE,OAAO,QAAQ,QAAQ,KAAK,CAAC,EAAE,IAAI,OAAK,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;AACnH;AAEO,SAAS,YAAY,OAAkB,UAA8C;AAC1F,QAAM,UAAU,IAAI,YAAY,KAAK;AACrC,QAAM,SAAS,QAAQ,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,aAAa,IAAI,GAAG,QAAQ,KAAK,YAAY,KAAK,EAAE;AACxG,QAAM,UAAU,CAAC,GAAG,IAAI,IAAI,OAAO,IAAI,CAAC,UAAU,MAAM,MAAM,CAAC,CAAC;AAChE,QAAM,WAAW,oBAAoB,QAAQ,UAAU,EAAE,OAAO,YAAY,QAAQ,MAAM,SAAS,QAAQ,CAAC;AAC5G,SAAO,IAAI,YAAY,SAAS,IAAI,CAAC,UAAU,MAAM,IAAI,CAAC;AAC5D;AAEO,SAAS,sBAAsB,OAAwB,WAAsD;AAClH,SAAO,UAAU,aAAa,OAAO,YAAY,MAAM,GAAG,UAAU,QAAQ,IAAI;AAClF;","names":[]}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+ var testing_api_exports = {};
16
+ module.exports = __toCommonJS(testing_api_exports);
17
+ //# sourceMappingURL=testing-api.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/testing-api.ts"],"sourcesContent":["/**\n * Project-augmentable object-shaped operation API exposed by testWood.\n *\n * Wood codegen augments this interface in each application with that\n * application's GeneratedWoodBridge contract.\n */\nexport interface WoodTestApi {}\n\n/**\n * Same operation tree as WoodTestApi, but every leaf accepts unknown input.\n * Use this only when a test intentionally attacks runtime validation with a\n * malformed payload; normal operation calls belong on TestWoodEnvironment.api.\n */\nexport type WoodTestRawApi<T = WoodTestApi> = {\n [K in keyof T]: T[K] extends (...args: infer _Args) => infer _Return\n ? (data?: unknown) => Promise<unknown>\n : T[K] extends object\n ? WoodTestRawApi<T[K]>\n : never;\n};\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Project-augmentable object-shaped operation API exposed by testWood.
3
+ *
4
+ * Wood codegen augments this interface in each application with that
5
+ * application's GeneratedWoodBridge contract.
6
+ */
7
+ interface WoodTestApi {
8
+ }
9
+ /**
10
+ * Same operation tree as WoodTestApi, but every leaf accepts unknown input.
11
+ * Use this only when a test intentionally attacks runtime validation with a
12
+ * malformed payload; normal operation calls belong on TestWoodEnvironment.api.
13
+ */
14
+ type WoodTestRawApi<T = WoodTestApi> = {
15
+ [K in keyof T]: T[K] extends (...args: infer _Args) => infer _Return ? (data?: unknown) => Promise<unknown> : T[K] extends object ? WoodTestRawApi<T[K]> : never;
16
+ };
17
+
18
+ export type { WoodTestApi, WoodTestRawApi };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Project-augmentable object-shaped operation API exposed by testWood.
3
+ *
4
+ * Wood codegen augments this interface in each application with that
5
+ * application's GeneratedWoodBridge contract.
6
+ */
7
+ interface WoodTestApi {
8
+ }
9
+ /**
10
+ * Same operation tree as WoodTestApi, but every leaf accepts unknown input.
11
+ * Use this only when a test intentionally attacks runtime validation with a
12
+ * malformed payload; normal operation calls belong on TestWoodEnvironment.api.
13
+ */
14
+ type WoodTestRawApi<T = WoodTestApi> = {
15
+ [K in keyof T]: T[K] extends (...args: infer _Args) => infer _Return ? (data?: unknown) => Promise<unknown> : T[K] extends object ? WoodTestRawApi<T[K]> : never;
16
+ };
17
+
18
+ export type { WoodTestApi, WoodTestRawApi };
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=testing-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types/config.ts"],"sourcesContent":["/** Configuration types for wood.config.yml */\n\n/** Top-level Wood configuration parsed from wood.config.yml */\nexport interface WoodConfig {\n root: string;\n outDir: string;\n app: {\n boot: string;\n watch: string[];\n };\n main: {\n entry: string;\n controllers: string;\n middleware: string;\n openapi: string;\n watch: string[];\n testing?: MainTestingConfig;\n };\n renderer: {\n openapi: string;\n componentDir: string;\n controllers: string;\n entry?: string;\n watch?: string[];\n testing?: RendererTestingConfig;\n };\n windows: Record<string, WindowDef>;\n database?: {\n path: string;\n migrations?: string;\n };\n assets?: string[];\n dev?: DevConfig;\n build?: ElectronBuilderConfig;\n observability?: ObservabilityConfig;\n}\n\n/**\n * Test-composition hooks for the main process (`main.testing`). Only the\n * application can know how its backend composes on a fresh IoC root; the\n * config names the module so `@noego/wood/testing`'s `testWood(configPath)`\n * finds it without any test-site wiring.\n */\nexport interface MainTestingConfig {\n /**\n * Module (config-relative path) whose default export composes the app's\n * backend on the root the test builder hands it. See `WoodComposeMain`\n * in `@noego/wood/testing`.\n */\n compose?: string;\n}\n\n/** Test-composition hooks for the renderer (`renderer.testing`). */\nexport interface RendererTestingConfig {\n /**\n * Module (config-relative path) whose default export mounts a page's real\n * component for a controller under a DOM driver. See `WoodPageHost` in\n * `@noego/wood/testing`.\n */\n host?: string;\n}\n\n/**\n * Renderer→main IPC trace batching policy. Owned here (wood.config.yml) per\n * the NoEgo observability architecture: the generated preload embeds the\n * resolved values but is not the configuration owner, and changing this policy\n * never changes instrumentation call sites or record semantics.\n */\nexport interface RendererTraceBatchingConfig {\n maxQueuedEvents: number;\n maxBatchEvents: number;\n acknowledgementTimeoutMs: number;\n retryLimit: number;\n retryBaseDelayMs: number;\n}\n\nexport interface ObservabilityConfig {\n trace?: {\n rendererToMain?: {\n batching?: RendererTraceBatchingConfig;\n };\n };\n}\n\n/** BrowserWindow definition from the `windows` section of wood.config.yml */\nexport interface WindowDef {\n title: string;\n width: number;\n height: number;\n defaultRoute: string;\n frame?: boolean;\n transparent?: boolean;\n resizable?: boolean;\n alwaysOnTop?: boolean;\n minWidth?: number;\n minHeight?: number;\n maxWidth?: number;\n maxHeight?: number;\n show?: boolean;\n parent?: string;\n modal?: boolean;\n vibrancy?: string;\n backgroundMaterial?: string;\n rememberBounds?: boolean;\n contextMenu?: 'native' | 'custom';\n acceptFirstMouse?: boolean;\n nativeQuitFallback?: boolean;\n titleBarStyle?: 'default' | 'hidden' | 'hiddenInset' | 'customButtonsOnHover';\n trafficLightPosition?: { x: number; y: number };\n titleBarOverlay?: boolean | { color?: string; symbolColor?: string; height?: number };\n}\n\n/** Dev-mode settings from the `dev` section of wood.config.yml */\nexport interface DevConfig {\n port?: number;\n watch?: boolean;\n splitServe?: boolean;\n electronArgs?: string[];\n inspectPort?: number;\n backendInspectPort?: number;\n}\n\n/** Electron-builder packaging configuration from the `build` section */\nexport interface ElectronBuilderConfig {\n appId: string;\n productName: string;\n mac?: Record<string, unknown>;\n win?: Record<string, unknown>;\n linux?: Record<string, unknown>;\n [key: string]: unknown;\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../../src/types/config.ts"],"sourcesContent":["/** Configuration types for wood.config.yml */\n\n/** Top-level Wood configuration parsed from wood.config.yml */\nexport interface WoodConfig {\n root: string;\n outDir: string;\n app: {\n boot: string;\n watch: string[];\n };\n main: {\n entry: string;\n controllers: string;\n middleware: string;\n openapi: string;\n watch: string[];\n testing?: MainTestingConfig;\n };\n renderer: {\n openapi: string;\n componentDir: string;\n /** Config-relative global styles for native renderer hosts. */\n css?: string[];\n controllers: string;\n /** Production renderer-root registration module. */\n compose?: string;\n entry?: string;\n watch?: string[];\n testing?: RendererTestingConfig;\n };\n windows: Record<string, WindowDef>;\n database?: {\n path: string;\n migrations?: string;\n };\n assets?: string[];\n dev?: DevConfig;\n build?: ElectronBuilderConfig;\n observability?: ObservabilityConfig;\n}\n\n/**\n * Test-composition hooks for the main process (`main.testing`). Only the\n * application can know how its backend composes on a fresh IoC root; the\n * config names the module so `@noego/wood/testing`'s `testWood(configPath)`\n * finds it without any test-site wiring.\n */\nexport interface MainTestingConfig {\n /**\n * Module (config-relative path) whose default export composes the app's\n * backend on the root the test builder hands it. See `WoodComposeMain`\n * in `@noego/wood/testing`.\n */\n compose?: string;\n}\n\n/** Test-composition hooks for the renderer (`renderer.testing`). */\nexport interface RendererTestingConfig {\n /**\n * Module (config-relative path) whose default export mounts a page's real\n * component for a controller under a DOM driver. See `WoodPageHost` in\n * `@noego/wood/testing`.\n */\n host?: string;\n}\n\n/**\n * Renderer→main IPC trace batching policy. Owned here (wood.config.yml) per\n * the NoEgo observability architecture: the generated preload embeds the\n * resolved values but is not the configuration owner, and changing this policy\n * never changes instrumentation call sites or record semantics.\n */\nexport interface RendererTraceBatchingConfig {\n maxQueuedEvents: number;\n maxBatchEvents: number;\n acknowledgementTimeoutMs: number;\n retryLimit: number;\n retryBaseDelayMs: number;\n}\n\nexport interface ObservabilityConfig {\n trace?: {\n rendererToMain?: {\n batching?: RendererTraceBatchingConfig;\n };\n };\n}\n\n/** BrowserWindow definition from the `windows` section of wood.config.yml */\nexport interface WindowDef {\n title: string;\n width: number;\n height: number;\n defaultRoute: string;\n frame?: boolean;\n transparent?: boolean;\n resizable?: boolean;\n alwaysOnTop?: boolean;\n minWidth?: number;\n minHeight?: number;\n maxWidth?: number;\n maxHeight?: number;\n show?: boolean;\n parent?: string;\n modal?: boolean;\n vibrancy?: string;\n backgroundMaterial?: string;\n rememberBounds?: boolean;\n contextMenu?: 'native' | 'custom';\n acceptFirstMouse?: boolean;\n nativeQuitFallback?: boolean;\n titleBarStyle?: 'default' | 'hidden' | 'hiddenInset' | 'customButtonsOnHover';\n trafficLightPosition?: { x: number; y: number };\n titleBarOverlay?: boolean | { color?: string; symbolColor?: string; height?: number };\n}\n\n/** Dev-mode settings from the `dev` section of wood.config.yml */\nexport interface DevConfig {\n port?: number;\n watch?: boolean;\n splitServe?: boolean;\n electronArgs?: string[];\n inspectPort?: number;\n backendInspectPort?: number;\n}\n\n/** Electron-builder packaging configuration from the `build` section */\nexport interface ElectronBuilderConfig {\n appId: string;\n productName: string;\n mac?: Record<string, unknown>;\n win?: Record<string, unknown>;\n linux?: Record<string, unknown>;\n [key: string]: unknown;\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -18,7 +18,11 @@ interface WoodConfig {
18
18
  renderer: {
19
19
  openapi: string;
20
20
  componentDir: string;
21
+ /** Config-relative global styles for native renderer hosts. */
22
+ css?: string[];
21
23
  controllers: string;
24
+ /** Production renderer-root registration module. */
25
+ compose?: string;
22
26
  entry?: string;
23
27
  watch?: string[];
24
28
  testing?: RendererTestingConfig;
@@ -18,7 +18,11 @@ interface WoodConfig {
18
18
  renderer: {
19
19
  openapi: string;
20
20
  componentDir: string;
21
+ /** Config-relative global styles for native renderer hosts. */
22
+ css?: string[];
21
23
  controllers: string;
24
+ /** Production renderer-root registration module. */
25
+ compose?: string;
22
26
  entry?: string;
23
27
  watch?: string[];
24
28
  testing?: RendererTestingConfig;