@noego/wood 0.4.9 → 0.5.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 (493) hide show
  1. package/README.md +118 -42
  2. package/bin/axe.js +313 -98
  3. package/dist/{loader/__fixtures__/layouts/app.load.cjs → automation/actions.cjs} +3 -13
  4. package/dist/automation/actions.cjs.map +1 -0
  5. package/dist/automation/actions.d.cts +57 -0
  6. package/dist/automation/actions.d.ts +57 -0
  7. package/dist/automation/actions.js +1 -0
  8. package/dist/automation/actions.js.map +1 -0
  9. package/dist/automation/actions_executor.cjs +101 -0
  10. package/dist/automation/actions_executor.cjs.map +1 -0
  11. package/dist/automation/actions_executor.d.cts +16 -0
  12. package/dist/automation/actions_executor.d.ts +16 -0
  13. package/dist/automation/actions_executor.js +76 -0
  14. package/dist/automation/actions_executor.js.map +1 -0
  15. package/dist/automation/connection.cjs +86 -0
  16. package/dist/automation/connection.cjs.map +1 -0
  17. package/dist/automation/connection.d.cts +18 -0
  18. package/dist/automation/connection.d.ts +18 -0
  19. package/dist/automation/connection.js +51 -0
  20. package/dist/automation/connection.js.map +1 -0
  21. package/dist/{middleware/__fixtures__/middleware/sequence.cjs → automation/errors.cjs} +25 -22
  22. package/dist/automation/errors.cjs.map +1 -0
  23. package/dist/automation/errors.d.cts +31 -0
  24. package/dist/automation/errors.d.ts +31 -0
  25. package/dist/automation/errors.js +24 -0
  26. package/dist/automation/errors.js.map +1 -0
  27. package/dist/automation/index.cjs +49 -0
  28. package/dist/automation/index.cjs.map +1 -0
  29. package/dist/automation/index.d.cts +16 -0
  30. package/dist/automation/index.d.ts +16 -0
  31. package/dist/automation/index.js +15 -0
  32. package/dist/automation/index.js.map +1 -0
  33. package/dist/automation/introspection_reader.cjs +75 -0
  34. package/dist/automation/introspection_reader.cjs.map +1 -0
  35. package/dist/automation/introspection_reader.d.cts +20 -0
  36. package/dist/automation/introspection_reader.d.ts +20 -0
  37. package/dist/automation/introspection_reader.js +48 -0
  38. package/dist/automation/introspection_reader.js.map +1 -0
  39. package/dist/automation/locator.cjs +102 -0
  40. package/dist/automation/locator.cjs.map +1 -0
  41. package/dist/automation/locator.d.cts +51 -0
  42. package/dist/automation/locator.d.ts +51 -0
  43. package/dist/automation/locator.js +75 -0
  44. package/dist/automation/locator.js.map +1 -0
  45. package/dist/{loader/__fixtures__/views/test/page.load.cjs → automation/observation.cjs} +3 -13
  46. package/dist/automation/observation.cjs.map +1 -0
  47. package/dist/automation/observation.d.cts +44 -0
  48. package/dist/automation/observation.d.ts +44 -0
  49. package/dist/automation/observation.js +1 -0
  50. package/dist/automation/observation.js.map +1 -0
  51. package/dist/{controller/__fixtures__/controllers/test.cjs → automation/receipts.cjs} +3 -15
  52. package/dist/automation/receipts.cjs.map +1 -0
  53. package/dist/automation/receipts.d.cts +27 -0
  54. package/dist/automation/receipts.d.ts +27 -0
  55. package/dist/automation/receipts.js +1 -0
  56. package/dist/automation/receipts.js.map +1 -0
  57. package/dist/automation/scenario.cjs +696 -0
  58. package/dist/automation/scenario.cjs.map +1 -0
  59. package/dist/automation/scenario.d.cts +89 -0
  60. package/dist/automation/scenario.d.ts +89 -0
  61. package/dist/automation/scenario.js +660 -0
  62. package/dist/automation/scenario.js.map +1 -0
  63. package/dist/automation/scrolling.cjs +17 -0
  64. package/dist/automation/scrolling.cjs.map +1 -0
  65. package/dist/automation/scrolling.d.cts +51 -0
  66. package/dist/automation/scrolling.d.ts +51 -0
  67. package/dist/automation/scrolling.js +1 -0
  68. package/dist/automation/scrolling.js.map +1 -0
  69. package/dist/automation/scrolling_executor.cjs +109 -0
  70. package/dist/automation/scrolling_executor.cjs.map +1 -0
  71. package/dist/automation/scrolling_executor.d.cts +13 -0
  72. package/dist/automation/scrolling_executor.d.ts +13 -0
  73. package/dist/automation/scrolling_executor.js +84 -0
  74. package/dist/automation/scrolling_executor.js.map +1 -0
  75. package/dist/automation/target_identity.cjs +17 -0
  76. package/dist/automation/target_identity.cjs.map +1 -0
  77. package/dist/automation/target_identity.d.cts +28 -0
  78. package/dist/automation/target_identity.d.ts +28 -0
  79. package/dist/automation/target_identity.js +1 -0
  80. package/dist/automation/target_identity.js.map +1 -0
  81. package/dist/automation/target_registry.cjs +148 -0
  82. package/dist/automation/target_registry.cjs.map +1 -0
  83. package/dist/automation/target_registry.d.cts +32 -0
  84. package/dist/automation/target_registry.d.ts +32 -0
  85. package/dist/automation/target_registry.js +122 -0
  86. package/dist/automation/target_registry.js.map +1 -0
  87. package/dist/automation/waits.cjs +17 -0
  88. package/dist/automation/waits.cjs.map +1 -0
  89. package/dist/automation/waits.d.cts +44 -0
  90. package/dist/automation/waits.d.ts +44 -0
  91. package/dist/automation/waits.js +1 -0
  92. package/dist/automation/waits.js.map +1 -0
  93. package/dist/automation/waits_executor.cjs +104 -0
  94. package/dist/automation/waits_executor.cjs.map +1 -0
  95. package/dist/automation/waits_executor.d.cts +14 -0
  96. package/dist/automation/waits_executor.d.ts +14 -0
  97. package/dist/automation/waits_executor.js +79 -0
  98. package/dist/automation/waits_executor.js.map +1 -0
  99. package/dist/bridge/backend_bridge.cjs.map +1 -1
  100. package/dist/bridge/backend_bridge.js.map +1 -1
  101. package/dist/client/index.cjs +78 -21
  102. package/dist/client/index.cjs.map +1 -1
  103. package/dist/client/index.d.cts +19 -3
  104. package/dist/client/index.d.ts +19 -3
  105. package/dist/client/index.js +80 -22
  106. package/dist/client/index.js.map +1 -1
  107. package/dist/client/renderer_log_transport.cjs +151 -0
  108. package/dist/client/renderer_log_transport.cjs.map +1 -0
  109. package/dist/client/renderer_log_transport.d.cts +54 -0
  110. package/dist/client/renderer_log_transport.d.ts +54 -0
  111. package/dist/client/renderer_log_transport.js +123 -0
  112. package/dist/client/renderer_log_transport.js.map +1 -0
  113. package/dist/codegen/controller_registration_generator.cjs +13 -2
  114. package/dist/codegen/controller_registration_generator.cjs.map +1 -1
  115. package/dist/codegen/controller_registration_generator.d.cts +12 -1
  116. package/dist/codegen/controller_registration_generator.d.ts +12 -1
  117. package/dist/codegen/controller_registration_generator.js +10 -1
  118. package/dist/codegen/controller_registration_generator.js.map +1 -1
  119. package/dist/codegen/index.d.cts +1 -0
  120. package/dist/codegen/index.d.ts +1 -0
  121. package/dist/codegen/preload_generator.cjs +13 -6
  122. package/dist/codegen/preload_generator.cjs.map +1 -1
  123. package/dist/codegen/preload_generator.d.cts +11 -2
  124. package/dist/codegen/preload_generator.d.ts +11 -2
  125. package/dist/codegen/preload_generator.js +13 -6
  126. package/dist/codegen/preload_generator.js.map +1 -1
  127. package/dist/codegen/renderer_app_generator.cjs +95 -44
  128. package/dist/codegen/renderer_app_generator.cjs.map +1 -1
  129. package/dist/codegen/renderer_app_generator.js +95 -44
  130. package/dist/codegen/renderer_app_generator.js.map +1 -1
  131. package/dist/codegen/type_generator.cjs +1 -0
  132. package/dist/codegen/type_generator.cjs.map +1 -1
  133. package/dist/codegen/type_generator.js +1 -0
  134. package/dist/codegen/type_generator.js.map +1 -1
  135. package/dist/config/config_parser.cjs +95 -4
  136. package/dist/config/config_parser.cjs.map +1 -1
  137. package/dist/config/config_parser.d.cts +10 -2
  138. package/dist/config/config_parser.d.ts +10 -2
  139. package/dist/config/config_parser.js +92 -3
  140. package/dist/config/config_parser.js.map +1 -1
  141. package/dist/config/index.cjs +6 -2
  142. package/dist/config/index.cjs.map +1 -1
  143. package/dist/config/index.d.cts +2 -2
  144. package/dist/config/index.d.ts +2 -2
  145. package/dist/config/index.js +8 -2
  146. package/dist/config/index.js.map +1 -1
  147. package/dist/controller/controller_resolver.cjs +51 -3
  148. package/dist/controller/controller_resolver.cjs.map +1 -1
  149. package/dist/controller/controller_resolver.d.cts +27 -4
  150. package/dist/controller/controller_resolver.d.ts +27 -4
  151. package/dist/controller/controller_resolver.js +48 -2
  152. package/dist/controller/controller_resolver.js.map +1 -1
  153. package/dist/controller/index.cjs +6 -2
  154. package/dist/controller/index.cjs.map +1 -1
  155. package/dist/controller/index.d.cts +1 -1
  156. package/dist/controller/index.d.ts +1 -1
  157. package/dist/controller/index.js +4 -2
  158. package/dist/controller/index.js.map +1 -1
  159. package/dist/dev/wood_dev_server.cjs +4 -1
  160. package/dist/dev/wood_dev_server.cjs.map +1 -1
  161. package/dist/dev/wood_dev_server.js +5 -2
  162. package/dist/dev/wood_dev_server.js.map +1 -1
  163. package/dist/dev/yaml_watcher.cjs +1 -1
  164. package/dist/dev/yaml_watcher.cjs.map +1 -1
  165. package/dist/dev/yaml_watcher.d.cts +4 -0
  166. package/dist/dev/yaml_watcher.d.ts +4 -0
  167. package/dist/dev/yaml_watcher.js +1 -1
  168. package/dist/dev/yaml_watcher.js.map +1 -1
  169. package/dist/frontend/frontend_lifecycle.cjs +74 -0
  170. package/dist/frontend/frontend_lifecycle.cjs.map +1 -0
  171. package/dist/frontend/frontend_lifecycle.d.cts +50 -0
  172. package/dist/frontend/frontend_lifecycle.d.ts +50 -0
  173. package/dist/frontend/frontend_lifecycle.js +50 -0
  174. package/dist/frontend/frontend_lifecycle.js.map +1 -0
  175. package/dist/frontend/frontend_page.cjs +122 -0
  176. package/dist/frontend/frontend_page.cjs.map +1 -0
  177. package/dist/frontend/frontend_page.d.cts +62 -0
  178. package/dist/frontend/frontend_page.d.ts +62 -0
  179. package/dist/frontend/frontend_page.js +98 -0
  180. package/dist/frontend/frontend_page.js.map +1 -0
  181. package/dist/frontend/frontend_surface.cjs +249 -0
  182. package/dist/frontend/frontend_surface.cjs.map +1 -0
  183. package/dist/frontend/frontend_surface.d.cts +64 -0
  184. package/dist/frontend/frontend_surface.d.ts +64 -0
  185. package/dist/frontend/frontend_surface.js +224 -0
  186. package/dist/frontend/frontend_surface.js.map +1 -0
  187. package/dist/frontend/index.cjs +52 -0
  188. package/dist/frontend/index.cjs.map +1 -0
  189. package/dist/frontend/index.d.cts +10 -0
  190. package/dist/frontend/index.d.ts +10 -0
  191. package/dist/frontend/index.js +19 -0
  192. package/dist/frontend/index.js.map +1 -0
  193. package/dist/frontend/page_catalog.cjs +135 -0
  194. package/dist/frontend/page_catalog.cjs.map +1 -0
  195. package/dist/frontend/page_catalog.d.cts +56 -0
  196. package/dist/frontend/page_catalog.d.ts +56 -0
  197. package/dist/frontend/page_catalog.js +108 -0
  198. package/dist/frontend/page_catalog.js.map +1 -0
  199. package/dist/frontend/tracked_transport.cjs +55 -0
  200. package/dist/frontend/tracked_transport.cjs.map +1 -0
  201. package/dist/frontend/tracked_transport.d.cts +36 -0
  202. package/dist/frontend/tracked_transport.d.ts +36 -0
  203. package/dist/frontend/tracked_transport.js +31 -0
  204. package/dist/frontend/tracked_transport.js.map +1 -0
  205. package/dist/frontend/work_registry.cjs +153 -0
  206. package/dist/frontend/work_registry.cjs.map +1 -0
  207. package/dist/frontend/work_registry.d.cts +70 -0
  208. package/dist/frontend/work_registry.d.ts +70 -0
  209. package/dist/frontend/work_registry.js +128 -0
  210. package/dist/frontend/work_registry.js.map +1 -0
  211. package/dist/index.cjs +24 -0
  212. package/dist/index.cjs.map +1 -1
  213. package/dist/index.d.cts +11 -7
  214. package/dist/index.d.ts +11 -7
  215. package/dist/index.js +27 -4
  216. package/dist/index.js.map +1 -1
  217. package/dist/main/index.cjs +10 -0
  218. package/dist/main/index.cjs.map +1 -1
  219. package/dist/main/index.d.cts +14 -2
  220. package/dist/main/index.d.ts +14 -2
  221. package/dist/main/index.js +16 -0
  222. package/dist/main/index.js.map +1 -1
  223. package/dist/middleware/middleware_resolver.cjs +22 -1
  224. package/dist/middleware/middleware_resolver.cjs.map +1 -1
  225. package/dist/middleware/middleware_resolver.d.cts +13 -1
  226. package/dist/middleware/middleware_resolver.d.ts +13 -1
  227. package/dist/middleware/middleware_resolver.js +22 -1
  228. package/dist/middleware/middleware_resolver.js.map +1 -1
  229. package/dist/navigation/automation_introspection.cjs +110 -0
  230. package/dist/navigation/automation_introspection.cjs.map +1 -0
  231. package/dist/navigation/automation_introspection.d.cts +60 -0
  232. package/dist/navigation/automation_introspection.d.ts +60 -0
  233. package/dist/navigation/automation_introspection.js +85 -0
  234. package/dist/navigation/automation_introspection.js.map +1 -0
  235. package/dist/navigation/index.cjs +10 -2
  236. package/dist/navigation/index.cjs.map +1 -1
  237. package/dist/navigation/index.d.cts +27 -1
  238. package/dist/navigation/index.d.ts +27 -1
  239. package/dist/navigation/index.js +6 -1
  240. package/dist/navigation/index.js.map +1 -1
  241. package/dist/{middleware/__fixtures__/middleware/auth.cjs → navigation/layout_preservation.cjs} +18 -20
  242. package/dist/navigation/layout_preservation.cjs.map +1 -0
  243. package/dist/navigation/layout_preservation.d.cts +2 -0
  244. package/dist/navigation/layout_preservation.d.ts +2 -0
  245. package/dist/navigation/layout_preservation.js +18 -0
  246. package/dist/navigation/layout_preservation.js.map +1 -0
  247. package/dist/parser/index.cjs +2 -0
  248. package/dist/parser/index.cjs.map +1 -1
  249. package/dist/parser/index.d.cts +1 -1
  250. package/dist/parser/index.d.ts +1 -1
  251. package/dist/parser/index.js +2 -1
  252. package/dist/parser/index.js.map +1 -1
  253. package/dist/parser/operations_parser.cjs +6 -0
  254. package/dist/parser/operations_parser.cjs.map +1 -1
  255. package/dist/parser/operations_parser.d.cts +9 -2
  256. package/dist/parser/operations_parser.d.ts +9 -2
  257. package/dist/parser/operations_parser.js +5 -0
  258. package/dist/parser/operations_parser.js.map +1 -1
  259. package/dist/parser/views_parser.cjs.map +1 -1
  260. package/dist/parser/views_parser.js.map +1 -1
  261. package/dist/router/index.d.cts +1 -0
  262. package/dist/router/index.d.ts +1 -0
  263. package/dist/router/wood_router.cjs +35 -3
  264. package/dist/router/wood_router.cjs.map +1 -1
  265. package/dist/router/wood_router.d.cts +15 -0
  266. package/dist/router/wood_router.d.ts +15 -0
  267. package/dist/router/wood_router.js +36 -4
  268. package/dist/router/wood_router.js.map +1 -1
  269. package/dist/runtime/get_container.cjs +9 -34
  270. package/dist/runtime/get_container.cjs.map +1 -1
  271. package/dist/runtime/get_container.d.cts +24 -4
  272. package/dist/runtime/get_container.d.ts +24 -4
  273. package/dist/runtime/get_container.js +8 -23
  274. package/dist/runtime/get_container.js.map +1 -1
  275. package/dist/runtime/index.cjs +9 -0
  276. package/dist/runtime/index.cjs.map +1 -1
  277. package/dist/runtime/index.d.cts +5 -2
  278. package/dist/runtime/index.d.ts +5 -2
  279. package/dist/runtime/index.js +10 -1
  280. package/dist/runtime/index.js.map +1 -1
  281. package/dist/runtime/renderer_config_extension.cjs +50 -0
  282. package/dist/runtime/renderer_config_extension.cjs.map +1 -0
  283. package/dist/runtime/renderer_config_extension.d.cts +19 -0
  284. package/dist/runtime/renderer_config_extension.d.ts +19 -0
  285. package/dist/runtime/renderer_config_extension.js +24 -0
  286. package/dist/runtime/renderer_config_extension.js.map +1 -0
  287. package/dist/runtime/renderer_log_batch_receiver.cjs +73 -0
  288. package/dist/runtime/renderer_log_batch_receiver.cjs.map +1 -0
  289. package/dist/runtime/renderer_log_batch_receiver.d.cts +29 -0
  290. package/dist/runtime/renderer_log_batch_receiver.d.ts +29 -0
  291. package/dist/runtime/renderer_log_batch_receiver.js +48 -0
  292. package/dist/runtime/renderer_log_batch_receiver.js.map +1 -0
  293. package/dist/runtime/renderer_trace_batch_receiver_registry.d.cts +1 -1
  294. package/dist/runtime/renderer_trace_batch_receiver_registry.d.ts +1 -1
  295. package/dist/runtime/runtime.cjs +14 -0
  296. package/dist/runtime/runtime.cjs.map +1 -1
  297. package/dist/runtime/runtime.d.cts +2 -1
  298. package/dist/runtime/runtime.d.ts +2 -1
  299. package/dist/runtime/runtime.js +14 -0
  300. package/dist/runtime/runtime.js.map +1 -1
  301. package/dist/stick/index.cjs.map +1 -1
  302. package/dist/stick/index.js.map +1 -1
  303. package/dist/testing/automation_assertions.cjs +417 -0
  304. package/dist/testing/automation_assertions.cjs.map +1 -0
  305. package/dist/testing/automation_assertions.d.cts +44 -0
  306. package/dist/testing/automation_assertions.d.ts +44 -0
  307. package/dist/testing/automation_assertions.js +385 -0
  308. package/dist/testing/automation_assertions.js.map +1 -0
  309. package/dist/testing/browser.cjs +130 -57
  310. package/dist/testing/browser.cjs.map +1 -1
  311. package/dist/testing/browser.d.cts +10 -4
  312. package/dist/testing/browser.d.ts +10 -4
  313. package/dist/testing/browser.js +132 -53
  314. package/dist/testing/browser.js.map +1 -1
  315. package/dist/testing/create_controller_harness.cjs +28 -8
  316. package/dist/testing/create_controller_harness.cjs.map +1 -1
  317. package/dist/testing/create_controller_harness.d.cts +18 -2
  318. package/dist/testing/create_controller_harness.d.ts +18 -2
  319. package/dist/testing/create_controller_harness.js +28 -8
  320. package/dist/testing/create_controller_harness.js.map +1 -1
  321. package/dist/testing/create_router_bridge.d.cts +1 -0
  322. package/dist/testing/create_router_bridge.d.ts +1 -0
  323. package/dist/testing/create_test_router.d.cts +1 -0
  324. package/dist/testing/create_test_router.d.ts +1 -0
  325. package/dist/testing/geometry.cjs +109 -0
  326. package/dist/testing/geometry.cjs.map +1 -0
  327. package/dist/testing/geometry.d.cts +45 -0
  328. package/dist/testing/geometry.d.ts +45 -0
  329. package/dist/testing/geometry.js +79 -0
  330. package/dist/testing/geometry.js.map +1 -0
  331. package/dist/testing/index.cjs +62 -2
  332. package/dist/testing/index.cjs.map +1 -1
  333. package/dist/testing/index.d.cts +23 -4
  334. package/dist/testing/index.d.ts +23 -4
  335. package/dist/testing/index.js +50 -2
  336. package/dist/testing/index.js.map +1 -1
  337. package/dist/{controller/__fixtures__/controllers/not_a_class.cjs → testing/test_wood.cjs} +15 -7
  338. package/dist/testing/test_wood.cjs.map +1 -0
  339. package/dist/testing/test_wood.d.cts +16 -0
  340. package/dist/testing/test_wood.d.ts +16 -0
  341. package/dist/testing/test_wood.js +12 -0
  342. package/dist/testing/test_wood.js.map +1 -0
  343. package/dist/testing/test_wood_config.cjs +272 -0
  344. package/dist/testing/test_wood_config.cjs.map +1 -0
  345. package/dist/testing/test_wood_config.d.cts +111 -0
  346. package/dist/testing/test_wood_config.d.ts +111 -0
  347. package/dist/testing/test_wood_config.js +247 -0
  348. package/dist/testing/test_wood_config.js.map +1 -0
  349. package/dist/testing/wood_config_source.cjs +146 -0
  350. package/dist/testing/wood_config_source.cjs.map +1 -0
  351. package/dist/testing/wood_config_source.d.cts +36 -0
  352. package/dist/testing/wood_config_source.d.ts +36 -0
  353. package/dist/testing/wood_config_source.js +112 -0
  354. package/dist/testing/wood_config_source.js.map +1 -0
  355. package/dist/testing/wood_env_renderer.cjs +210 -0
  356. package/dist/testing/wood_env_renderer.cjs.map +1 -0
  357. package/dist/testing/wood_env_renderer.d.cts +74 -0
  358. package/dist/testing/wood_env_renderer.d.ts +74 -0
  359. package/dist/testing/wood_env_renderer.js +188 -0
  360. package/dist/testing/wood_env_renderer.js.map +1 -0
  361. package/dist/testing/wood_test_selection.cjs +94 -0
  362. package/dist/testing/wood_test_selection.cjs.map +1 -0
  363. package/dist/testing/wood_test_selection.d.cts +39 -0
  364. package/dist/testing/wood_test_selection.d.ts +39 -0
  365. package/dist/testing/wood_test_selection.js +68 -0
  366. package/dist/testing/wood_test_selection.js.map +1 -0
  367. package/dist/trace-testing/index.d.cts +1 -2
  368. package/dist/trace-testing/index.d.ts +1 -2
  369. package/dist/trace-testing/trace_recorder.cjs +1 -1
  370. package/dist/trace-testing/trace_recorder.cjs.map +1 -1
  371. package/dist/trace-testing/trace_recorder.d.cts +1 -2
  372. package/dist/trace-testing/trace_recorder.d.ts +1 -2
  373. package/dist/trace-testing/trace_recorder.js +1 -1
  374. package/dist/trace-testing/trace_recorder.js.map +1 -1
  375. package/dist/trace-transport/index.d.cts +1 -1
  376. package/dist/trace-transport/index.d.ts +1 -1
  377. package/dist/{trace_hub-Cob54qRx.d.cts → trace_hub-Cpo_nVze.d.cts} +21 -1
  378. package/dist/{trace_hub-Cob54qRx.d.ts → trace_hub-Cpo_nVze.d.ts} +21 -1
  379. package/dist/tracing/index.cjs +9 -2
  380. package/dist/tracing/index.cjs.map +1 -1
  381. package/dist/tracing/index.d.cts +3 -2
  382. package/dist/tracing/index.d.ts +3 -2
  383. package/dist/tracing/index.js +7 -1
  384. package/dist/tracing/index.js.map +1 -1
  385. package/dist/tracing/renderer_trace_batch_host.d.cts +1 -1
  386. package/dist/tracing/renderer_trace_batch_host.d.ts +1 -1
  387. package/dist/tracing/renderer_trace_batch_transport.cjs +48 -6
  388. package/dist/tracing/renderer_trace_batch_transport.cjs.map +1 -1
  389. package/dist/tracing/renderer_trace_batch_transport.d.cts +17 -1
  390. package/dist/tracing/renderer_trace_batch_transport.d.ts +17 -1
  391. package/dist/tracing/renderer_trace_batch_transport.js +48 -6
  392. package/dist/tracing/renderer_trace_batch_transport.js.map +1 -1
  393. package/dist/tracing/trace_batch_adapter.cjs +110 -0
  394. package/dist/tracing/trace_batch_adapter.cjs.map +1 -0
  395. package/dist/tracing/trace_batch_adapter.d.cts +36 -0
  396. package/dist/tracing/trace_batch_adapter.d.ts +36 -0
  397. package/dist/tracing/trace_batch_adapter.js +86 -0
  398. package/dist/tracing/trace_batch_adapter.js.map +1 -0
  399. package/dist/tracing/trace_commit_writer.d.cts +1 -1
  400. package/dist/tracing/trace_commit_writer.d.ts +1 -1
  401. package/dist/tracing/trace_hub.cjs +87 -20
  402. package/dist/tracing/trace_hub.cjs.map +1 -1
  403. package/dist/tracing/trace_hub.d.cts +1 -1
  404. package/dist/tracing/trace_hub.d.ts +1 -1
  405. package/dist/tracing/trace_hub.js +85 -20
  406. package/dist/tracing/trace_hub.js.map +1 -1
  407. package/dist/tracing/trace_provider.cjs +21 -6
  408. package/dist/tracing/trace_provider.cjs.map +1 -1
  409. package/dist/tracing/trace_provider.d.cts +13 -4
  410. package/dist/tracing/trace_provider.d.ts +13 -4
  411. package/dist/tracing/trace_provider.js +22 -7
  412. package/dist/tracing/trace_provider.js.map +1 -1
  413. package/dist/tracing/types/wood_trace_batch.types.cjs.map +1 -1
  414. package/dist/tracing/types/wood_trace_batch.types.d.cts +15 -1
  415. package/dist/tracing/types/wood_trace_batch.types.d.ts +15 -1
  416. package/dist/tracing/types/wood_trace_sink.types.d.cts +1 -1
  417. package/dist/tracing/types/wood_trace_sink.types.d.ts +1 -1
  418. package/dist/tracing/wood_trace_batch_contract.cjs +2 -0
  419. package/dist/tracing/wood_trace_batch_contract.cjs.map +1 -1
  420. package/dist/tracing/wood_trace_batch_contract.d.cts +1 -1
  421. package/dist/tracing/wood_trace_batch_contract.d.ts +1 -1
  422. package/dist/tracing/wood_trace_batch_contract.js +2 -0
  423. package/dist/tracing/wood_trace_batch_contract.js.map +1 -1
  424. package/dist/transport/build_transport_bridge.cjs +4 -2
  425. package/dist/transport/build_transport_bridge.cjs.map +1 -1
  426. package/dist/transport/build_transport_bridge.d.cts +7 -1
  427. package/dist/transport/build_transport_bridge.d.ts +7 -1
  428. package/dist/transport/build_transport_bridge.js +2 -1
  429. package/dist/transport/build_transport_bridge.js.map +1 -1
  430. package/dist/transport/in_process_router_transport.d.cts +1 -0
  431. package/dist/transport/in_process_router_transport.d.ts +1 -0
  432. package/dist/transport/index.d.cts +1 -0
  433. package/dist/transport/index.d.ts +1 -0
  434. package/dist/types/config.cjs.map +1 -1
  435. package/dist/types/config.d.cts +47 -1
  436. package/dist/types/config.d.ts +47 -1
  437. package/dist/types/context.cjs +12 -0
  438. package/dist/types/context.cjs.map +1 -1
  439. package/dist/types/context.d.cts +27 -1
  440. package/dist/types/context.d.ts +27 -1
  441. package/dist/types/context.js +4 -0
  442. package/dist/types/context.js.map +1 -1
  443. package/dist/types/index.d.cts +2 -2
  444. package/dist/types/index.d.ts +2 -2
  445. package/dist/types/operations.cjs.map +1 -1
  446. package/dist/types/operations.d.cts +2 -0
  447. package/dist/types/operations.d.ts +2 -0
  448. package/docs/axe.md +706 -0
  449. package/package.json +19 -5
  450. package/src/components/NavigationShell.scopes.browser.test.ts +363 -0
  451. package/src/components/NavigationShell.svelte +126 -49
  452. package/dist/controller/__fixtures__/controllers/chat.cjs +0 -32
  453. package/dist/controller/__fixtures__/controllers/chat.cjs.map +0 -1
  454. package/dist/controller/__fixtures__/controllers/chat.d.cts +0 -11
  455. package/dist/controller/__fixtures__/controllers/chat.d.ts +0 -11
  456. package/dist/controller/__fixtures__/controllers/chat.js +0 -12
  457. package/dist/controller/__fixtures__/controllers/chat.js.map +0 -1
  458. package/dist/controller/__fixtures__/controllers/not_a_class.cjs.map +0 -1
  459. package/dist/controller/__fixtures__/controllers/not_a_class.d.cts +0 -3
  460. package/dist/controller/__fixtures__/controllers/not_a_class.d.ts +0 -3
  461. package/dist/controller/__fixtures__/controllers/not_a_class.js +0 -5
  462. package/dist/controller/__fixtures__/controllers/not_a_class.js.map +0 -1
  463. package/dist/controller/__fixtures__/controllers/settings.controller.cjs +0 -32
  464. package/dist/controller/__fixtures__/controllers/settings.controller.cjs.map +0 -1
  465. package/dist/controller/__fixtures__/controllers/settings.controller.d.cts +0 -12
  466. package/dist/controller/__fixtures__/controllers/settings.controller.d.ts +0 -12
  467. package/dist/controller/__fixtures__/controllers/settings.controller.js +0 -12
  468. package/dist/controller/__fixtures__/controllers/settings.controller.js.map +0 -1
  469. package/dist/controller/__fixtures__/controllers/test.cjs.map +0 -1
  470. package/dist/controller/__fixtures__/controllers/test.d.cts +0 -7
  471. package/dist/controller/__fixtures__/controllers/test.d.ts +0 -7
  472. package/dist/controller/__fixtures__/controllers/test.js +0 -9
  473. package/dist/controller/__fixtures__/controllers/test.js.map +0 -1
  474. package/dist/loader/__fixtures__/layouts/app.load.cjs.map +0 -1
  475. package/dist/loader/__fixtures__/layouts/app.load.d.cts +0 -5
  476. package/dist/loader/__fixtures__/layouts/app.load.d.ts +0 -5
  477. package/dist/loader/__fixtures__/layouts/app.load.js +0 -7
  478. package/dist/loader/__fixtures__/layouts/app.load.js.map +0 -1
  479. package/dist/loader/__fixtures__/views/test/page.load.cjs.map +0 -1
  480. package/dist/loader/__fixtures__/views/test/page.load.d.cts +0 -6
  481. package/dist/loader/__fixtures__/views/test/page.load.d.ts +0 -6
  482. package/dist/loader/__fixtures__/views/test/page.load.js +0 -7
  483. package/dist/loader/__fixtures__/views/test/page.load.js.map +0 -1
  484. package/dist/middleware/__fixtures__/middleware/auth.cjs.map +0 -1
  485. package/dist/middleware/__fixtures__/middleware/auth.d.cts +0 -6
  486. package/dist/middleware/__fixtures__/middleware/auth.d.ts +0 -6
  487. package/dist/middleware/__fixtures__/middleware/auth.js +0 -19
  488. package/dist/middleware/__fixtures__/middleware/auth.js.map +0 -1
  489. package/dist/middleware/__fixtures__/middleware/sequence.cjs.map +0 -1
  490. package/dist/middleware/__fixtures__/middleware/sequence.d.cts +0 -7
  491. package/dist/middleware/__fixtures__/middleware/sequence.d.ts +0 -7
  492. package/dist/middleware/__fixtures__/middleware/sequence.js +0 -21
  493. package/dist/middleware/__fixtures__/middleware/sequence.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/stick/index.ts"],"sourcesContent":["import './allow_cli.js';\n// Type-only import — erased at runtime, won't trigger module loading\nimport type { WoodStaticRenderer } from './static_renderer.js';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { resolveImageRendererTemplate } from './template_resolver.js';\n\nexport type { WoodStaticRenderer };\nexport type {\n WoodStaticRendererConfig,\n WoodRenderOptions,\n WoodRenderToPageOptions,\n WoodRenderResult,\n} from './static_renderer';\n\n// ─────────────────────────────────────────────────────────────\n// Error Classes\n// ─────────────────────────────────────────────────────────────\n\nexport class PlaywrightNotInstalledError extends Error {\n name = 'PlaywrightNotInstalledError' as const;\n constructor() {\n super(\n 'ImageRenderer requires Playwright. Install it with:\\n' +\n ' npm install playwright\\n' +\n ' npx playwright install chromium'\n );\n }\n}\n\nexport class BrowserLaunchError extends Error {\n name = 'BrowserLaunchError' as const;\n constructor(message: string, public cause?: Error) {\n super(message);\n }\n}\n\nexport class RenderTimeoutError extends Error {\n name = 'RenderTimeoutError' as const;\n constructor(timeoutMs: number) {\n super(`Render timed out after ${timeoutMs}ms`);\n }\n}\n\nexport class RenderError extends Error {\n name = 'RenderError' as const;\n constructor(message: string, public cause?: Error) {\n super(message);\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────\n\nexport interface ImageRendererConfig {\n /** Output directory for screenshots */\n outputDir: string;\n /** Default width (default: 1920) */\n width?: number;\n /** Default height (default: 1080) */\n height?: number;\n /** Device scale factor for retina (default: 1) */\n deviceScaleFactor?: number;\n /** Image format (default: 'png') */\n format?: 'png' | 'jpeg';\n /** JPEG quality 0-100 (default: 80) */\n quality?: number;\n /** Wait condition (default: 'networkidle') */\n waitUntil?: 'load' | 'domcontentloaded' | 'networkidle';\n /** Timeout in ms (default: 10000) */\n timeoutMs?: number;\n /** Custom HTML template with {{{HEAD}}}, {{{CSS}}}, {{{APP}}} placeholders */\n template?: string;\n\n // Static renderer config (one of these)\n /** Pre-created WoodStaticRenderer instance */\n staticRenderer?: WoodStaticRenderer;\n /** OR: Path to views.yaml */\n viewsConfig?: string;\n /**\n * Component directory (required if viewsConfig provided).\n * When template is omitted, stick auto-loads <componentDir>/index.html and\n * inlines <componentDir>/styles.css when present.\n */\n componentDir?: string;\n /** Asset path mappings (e.g., { '/images': ['public/images'] }) */\n assets?: Record<string, string[]>;\n}\n\nexport interface CaptureOptions {\n /** View component data */\n view?: any;\n /** Layout data (one object per layout) */\n layout?: any[];\n /** Wood bridge object passed as a prop to layouts and views */\n wood?: any;\n /** Override width */\n width?: number;\n /** Override height */\n height?: number;\n /** Capture full page (default: true) */\n fullPage?: boolean;\n /** Callback executed after page load, before screenshot. Receives the Playwright page object. */\n beforeCapture?: (page: any) => Promise<void>;\n}\n\nexport interface CaptureHtmlOptions {\n /** Override width */\n width?: number;\n /** Override height */\n height?: number;\n /** Capture full page (default: true) */\n fullPage?: boolean;\n /** Callback executed after page load, before screenshot. Receives the Playwright page object. */\n beforeCapture?: (page: any) => Promise<void>;\n}\n\ninterface CaptureResult {\n /** Raw image buffer */\n buffer: Buffer;\n /** Path where image was saved */\n path: string;\n}\n\n// ─────────────────────────────────────────────────────────────\n// Playwright Loader\n// ─────────────────────────────────────────────────────────────\n\ntype PlaywrightModule = typeof import('playwright');\n\nasync function loadPlaywright(): Promise<PlaywrightModule> {\n try {\n const playwright = await import('playwright');\n return playwright;\n } catch {\n throw new PlaywrightNotInstalledError();\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Content Type Helper\n// ─────────────────────────────────────────────────────────────\n\nfunction getContentType(filePath: string): string {\n const ext = path.extname(filePath).toLowerCase();\n const types: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.css': 'text/css',\n '.js': 'application/javascript',\n '.json': 'application/json',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n };\n return types[ext] || 'application/octet-stream';\n}\n\n// ─────────────────────────────────────────────────────────────\n// ImageRenderer Class\n// ─────────────────────────────────────────────────────────────\n\nexport class ImageRenderer {\n private browser: any;\n private staticRenderer: WoodStaticRenderer;\n private config: Required<Omit<ImageRendererConfig, 'staticRenderer' | 'viewsConfig' | 'componentDir' | 'template' | 'assets'>> & {\n outputDir: string;\n template?: string;\n assets?: Record<string, string[]>;\n };\n\n constructor(\n browser: any,\n staticRenderer: WoodStaticRenderer,\n config: ImageRendererConfig\n ) {\n this.browser = browser;\n this.staticRenderer = staticRenderer;\n this.config = {\n outputDir: config.outputDir,\n width: config.width ?? 1920,\n height: config.height ?? 1080,\n deviceScaleFactor: config.deviceScaleFactor ?? 1,\n format: config.format ?? 'png',\n quality: config.quality ?? 80,\n waitUntil: config.waitUntil ?? 'networkidle',\n timeoutMs: config.timeoutMs ?? 10000,\n template: config.template,\n assets: config.assets,\n };\n }\n\n /**\n * Capture a view by dot-path key and save to outputDir\n */\n async capture(\n name: string,\n viewKey: string,\n options?: CaptureOptions\n ): Promise<CaptureResult> {\n const { view, layout, wood } = options ?? {};\n const html = await this.staticRenderer.renderToPage({\n viewKey,\n data: { view, layout },\n wood,\n template: this.config.template,\n });\n\n return this.captureHtmlInternal(name, html, options);\n }\n\n /**\n * Capture raw HTML and save to outputDir\n */\n async captureHtml(\n name: string,\n html: string,\n options?: CaptureHtmlOptions\n ): Promise<CaptureResult> {\n return this.captureHtmlInternal(name, html, options);\n }\n\n /**\n * Internal method to capture HTML to image\n */\n private async captureHtmlInternal(\n name: string,\n html: string,\n options?: CaptureHtmlOptions\n ): Promise<CaptureResult> {\n const width = options?.width ?? this.config.width;\n const height = options?.height ?? this.config.height;\n\n let context: any;\n let page: any;\n\n try {\n context = await this.browser.newContext({\n viewport: { width, height },\n deviceScaleFactor: this.config.deviceScaleFactor,\n });\n\n page = await context.newPage();\n\n // Route Interception Strategy:\n // We use page.goto() with a fake URL instead of page.setContent() because\n // setContent() has no base URL, so relative paths can't resolve.\n const FAKE_BASE_URL = 'http://stick-renderer/';\n\n await page.route(FAKE_BASE_URL, async (route: any) => {\n await route.fulfill({\n body: html,\n contentType: 'text/html',\n });\n });\n\n // Asset route interception\n if (this.config.assets) {\n for (const [urlPath, fsPaths] of Object.entries(this.config.assets)) {\n await page.route(`**${urlPath}/**`, async (route: any) => {\n const url = new URL(route.request().url());\n const relativePath = url.pathname.replace(urlPath, '');\n\n for (const fsPath of fsPaths) {\n const filePath = path.join(fsPath, relativePath);\n try {\n const body = await fs.promises.readFile(filePath);\n const contentType = getContentType(filePath);\n await route.fulfill({ body, contentType });\n return;\n } catch {\n // File not found in this path, try the next one\n }\n }\n\n await route.abort('filenotfound');\n });\n }\n }\n\n const waitUntilMapping = {\n 'load': 'load',\n 'domcontentloaded': 'domcontentloaded',\n 'networkidle': 'networkidle',\n } as const;\n\n try {\n await page.goto(FAKE_BASE_URL, {\n waitUntil: waitUntilMapping[this.config.waitUntil],\n timeout: this.config.timeoutMs,\n });\n } catch (error) {\n if (error instanceof Error && error.message.includes('timeout')) {\n throw new RenderTimeoutError(this.config.timeoutMs);\n }\n throw new RenderError(\n 'Failed to render HTML content',\n error instanceof Error ? error : undefined\n );\n }\n\n if (options?.beforeCapture) {\n await options.beforeCapture(page);\n }\n\n const screenshotOptions: {\n type: 'png' | 'jpeg';\n quality?: number;\n fullPage: boolean;\n } = {\n type: this.config.format,\n fullPage: options?.fullPage ?? true,\n };\n\n if (this.config.format === 'jpeg') {\n screenshotOptions.quality = this.config.quality;\n }\n\n const screenshot = await page.screenshot(screenshotOptions);\n const buffer = Buffer.from(screenshot);\n\n const filename = `${name}@${width}x${height}.${this.config.format}`;\n const outputPath = path.join(this.config.outputDir, filename);\n\n await fs.promises.mkdir(this.config.outputDir, { recursive: true });\n await fs.promises.writeFile(outputPath, buffer);\n\n return { buffer, path: outputPath };\n\n } finally {\n if (page) {\n await page.close().catch(() => {});\n }\n if (context) {\n await context.close().catch(() => {});\n }\n }\n }\n\n /**\n * Close browser and clean up resources\n */\n async close(): Promise<void> {\n if (this.browser) {\n await this.browser.close().catch(() => {});\n }\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Factory Function\n// ─────────────────────────────────────────────────────────────\n\nexport async function createImageRenderer(\n config: ImageRendererConfig\n): Promise<ImageRenderer> {\n const resolvedTemplate = resolveImageRendererTemplate({\n template: config.template,\n componentDir: config.componentDir,\n });\n const resolvedConfig: ImageRendererConfig = {\n ...config,\n template: resolvedTemplate,\n };\n\n const playwright = await loadPlaywright();\n\n let browser: any;\n try {\n browser = await playwright.chromium.launch({\n headless: true,\n });\n } catch (error) {\n throw new BrowserLaunchError(\n 'Failed to launch Chromium. Ensure it is installed with: npx playwright install chromium',\n error instanceof Error ? error : undefined\n );\n }\n\n let staticRenderer: WoodStaticRenderer;\n if (resolvedConfig.staticRenderer) {\n staticRenderer = resolvedConfig.staticRenderer;\n } else if (resolvedConfig.viewsConfig && resolvedConfig.componentDir) {\n const { createWoodStaticRenderer } = await import('./static_renderer.js');\n staticRenderer = createWoodStaticRenderer({\n viewsConfig: resolvedConfig.viewsConfig,\n componentDir: resolvedConfig.componentDir,\n });\n } else {\n throw new Error(\n 'ImageRendererConfig requires either staticRenderer or both viewsConfig and componentDir'\n );\n }\n\n return new ImageRenderer(browser, staticRenderer, resolvedConfig);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/stick/index.ts"],"sourcesContent":["import './allow_cli.js';\n// Type-only import — erased at runtime, won't trigger module loading\nimport type { WoodStaticRenderer } from './static_renderer.js';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { resolveImageRendererTemplate } from './template_resolver.js';\n\nexport type { WoodStaticRenderer };\nexport type {\n WoodStaticRendererConfig,\n WoodRenderOptions,\n WoodRenderToPageOptions,\n WoodRenderResult,\n} from './static_renderer.js';\n\n// ─────────────────────────────────────────────────────────────\n// Error Classes\n// ─────────────────────────────────────────────────────────────\n\nexport class PlaywrightNotInstalledError extends Error {\n name = 'PlaywrightNotInstalledError' as const;\n constructor() {\n super(\n 'ImageRenderer requires Playwright. Install it with:\\n' +\n ' npm install playwright\\n' +\n ' npx playwright install chromium'\n );\n }\n}\n\nexport class BrowserLaunchError extends Error {\n name = 'BrowserLaunchError' as const;\n constructor(message: string, public cause?: Error) {\n super(message);\n }\n}\n\nexport class RenderTimeoutError extends Error {\n name = 'RenderTimeoutError' as const;\n constructor(timeoutMs: number) {\n super(`Render timed out after ${timeoutMs}ms`);\n }\n}\n\nexport class RenderError extends Error {\n name = 'RenderError' as const;\n constructor(message: string, public cause?: Error) {\n super(message);\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────\n\nexport interface ImageRendererConfig {\n /** Output directory for screenshots */\n outputDir: string;\n /** Default width (default: 1920) */\n width?: number;\n /** Default height (default: 1080) */\n height?: number;\n /** Device scale factor for retina (default: 1) */\n deviceScaleFactor?: number;\n /** Image format (default: 'png') */\n format?: 'png' | 'jpeg';\n /** JPEG quality 0-100 (default: 80) */\n quality?: number;\n /** Wait condition (default: 'networkidle') */\n waitUntil?: 'load' | 'domcontentloaded' | 'networkidle';\n /** Timeout in ms (default: 10000) */\n timeoutMs?: number;\n /** Custom HTML template with {{{HEAD}}}, {{{CSS}}}, {{{APP}}} placeholders */\n template?: string;\n\n // Static renderer config (one of these)\n /** Pre-created WoodStaticRenderer instance */\n staticRenderer?: WoodStaticRenderer;\n /** OR: Path to views.yaml */\n viewsConfig?: string;\n /**\n * Component directory (required if viewsConfig provided).\n * When template is omitted, stick auto-loads <componentDir>/index.html and\n * inlines <componentDir>/styles.css when present.\n */\n componentDir?: string;\n /** Asset path mappings (e.g., { '/images': ['public/images'] }) */\n assets?: Record<string, string[]>;\n}\n\nexport interface CaptureOptions {\n /** View component data */\n view?: any;\n /** Layout data (one object per layout) */\n layout?: any[];\n /** Wood bridge object passed as a prop to layouts and views */\n wood?: any;\n /** Override width */\n width?: number;\n /** Override height */\n height?: number;\n /** Capture full page (default: true) */\n fullPage?: boolean;\n /** Callback executed after page load, before screenshot. Receives the Playwright page object. */\n beforeCapture?: (page: any) => Promise<void>;\n}\n\nexport interface CaptureHtmlOptions {\n /** Override width */\n width?: number;\n /** Override height */\n height?: number;\n /** Capture full page (default: true) */\n fullPage?: boolean;\n /** Callback executed after page load, before screenshot. Receives the Playwright page object. */\n beforeCapture?: (page: any) => Promise<void>;\n}\n\ninterface CaptureResult {\n /** Raw image buffer */\n buffer: Buffer;\n /** Path where image was saved */\n path: string;\n}\n\n// ─────────────────────────────────────────────────────────────\n// Playwright Loader\n// ─────────────────────────────────────────────────────────────\n\ntype PlaywrightModule = typeof import('playwright');\n\nasync function loadPlaywright(): Promise<PlaywrightModule> {\n try {\n const playwright = await import('playwright');\n return playwright;\n } catch {\n throw new PlaywrightNotInstalledError();\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Content Type Helper\n// ─────────────────────────────────────────────────────────────\n\nfunction getContentType(filePath: string): string {\n const ext = path.extname(filePath).toLowerCase();\n const types: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.css': 'text/css',\n '.js': 'application/javascript',\n '.json': 'application/json',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n };\n return types[ext] || 'application/octet-stream';\n}\n\n// ─────────────────────────────────────────────────────────────\n// ImageRenderer Class\n// ─────────────────────────────────────────────────────────────\n\nexport class ImageRenderer {\n private browser: any;\n private staticRenderer: WoodStaticRenderer;\n private config: Required<Omit<ImageRendererConfig, 'staticRenderer' | 'viewsConfig' | 'componentDir' | 'template' | 'assets'>> & {\n outputDir: string;\n template?: string;\n assets?: Record<string, string[]>;\n };\n\n constructor(\n browser: any,\n staticRenderer: WoodStaticRenderer,\n config: ImageRendererConfig\n ) {\n this.browser = browser;\n this.staticRenderer = staticRenderer;\n this.config = {\n outputDir: config.outputDir,\n width: config.width ?? 1920,\n height: config.height ?? 1080,\n deviceScaleFactor: config.deviceScaleFactor ?? 1,\n format: config.format ?? 'png',\n quality: config.quality ?? 80,\n waitUntil: config.waitUntil ?? 'networkidle',\n timeoutMs: config.timeoutMs ?? 10000,\n template: config.template,\n assets: config.assets,\n };\n }\n\n /**\n * Capture a view by dot-path key and save to outputDir\n */\n async capture(\n name: string,\n viewKey: string,\n options?: CaptureOptions\n ): Promise<CaptureResult> {\n const { view, layout, wood } = options ?? {};\n const html = await this.staticRenderer.renderToPage({\n viewKey,\n data: { view, layout },\n wood,\n template: this.config.template,\n });\n\n return this.captureHtmlInternal(name, html, options);\n }\n\n /**\n * Capture raw HTML and save to outputDir\n */\n async captureHtml(\n name: string,\n html: string,\n options?: CaptureHtmlOptions\n ): Promise<CaptureResult> {\n return this.captureHtmlInternal(name, html, options);\n }\n\n /**\n * Internal method to capture HTML to image\n */\n private async captureHtmlInternal(\n name: string,\n html: string,\n options?: CaptureHtmlOptions\n ): Promise<CaptureResult> {\n const width = options?.width ?? this.config.width;\n const height = options?.height ?? this.config.height;\n\n let context: any;\n let page: any;\n\n try {\n context = await this.browser.newContext({\n viewport: { width, height },\n deviceScaleFactor: this.config.deviceScaleFactor,\n });\n\n page = await context.newPage();\n\n // Route Interception Strategy:\n // We use page.goto() with a fake URL instead of page.setContent() because\n // setContent() has no base URL, so relative paths can't resolve.\n const FAKE_BASE_URL = 'http://stick-renderer/';\n\n await page.route(FAKE_BASE_URL, async (route: any) => {\n await route.fulfill({\n body: html,\n contentType: 'text/html',\n });\n });\n\n // Asset route interception\n if (this.config.assets) {\n for (const [urlPath, fsPaths] of Object.entries(this.config.assets)) {\n await page.route(`**${urlPath}/**`, async (route: any) => {\n const url = new URL(route.request().url());\n const relativePath = url.pathname.replace(urlPath, '');\n\n for (const fsPath of fsPaths) {\n const filePath = path.join(fsPath, relativePath);\n try {\n const body = await fs.promises.readFile(filePath);\n const contentType = getContentType(filePath);\n await route.fulfill({ body, contentType });\n return;\n } catch {\n // File not found in this path, try the next one\n }\n }\n\n await route.abort('filenotfound');\n });\n }\n }\n\n const waitUntilMapping = {\n 'load': 'load',\n 'domcontentloaded': 'domcontentloaded',\n 'networkidle': 'networkidle',\n } as const;\n\n try {\n await page.goto(FAKE_BASE_URL, {\n waitUntil: waitUntilMapping[this.config.waitUntil],\n timeout: this.config.timeoutMs,\n });\n } catch (error) {\n if (error instanceof Error && error.message.includes('timeout')) {\n throw new RenderTimeoutError(this.config.timeoutMs);\n }\n throw new RenderError(\n 'Failed to render HTML content',\n error instanceof Error ? error : undefined\n );\n }\n\n if (options?.beforeCapture) {\n await options.beforeCapture(page);\n }\n\n const screenshotOptions: {\n type: 'png' | 'jpeg';\n quality?: number;\n fullPage: boolean;\n } = {\n type: this.config.format,\n fullPage: options?.fullPage ?? true,\n };\n\n if (this.config.format === 'jpeg') {\n screenshotOptions.quality = this.config.quality;\n }\n\n const screenshot = await page.screenshot(screenshotOptions);\n const buffer = Buffer.from(screenshot);\n\n const filename = `${name}@${width}x${height}.${this.config.format}`;\n const outputPath = path.join(this.config.outputDir, filename);\n\n await fs.promises.mkdir(this.config.outputDir, { recursive: true });\n await fs.promises.writeFile(outputPath, buffer);\n\n return { buffer, path: outputPath };\n\n } finally {\n if (page) {\n await page.close().catch(() => {});\n }\n if (context) {\n await context.close().catch(() => {});\n }\n }\n }\n\n /**\n * Close browser and clean up resources\n */\n async close(): Promise<void> {\n if (this.browser) {\n await this.browser.close().catch(() => {});\n }\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Factory Function\n// ─────────────────────────────────────────────────────────────\n\nexport async function createImageRenderer(\n config: ImageRendererConfig\n): Promise<ImageRenderer> {\n const resolvedTemplate = resolveImageRendererTemplate({\n template: config.template,\n componentDir: config.componentDir,\n });\n const resolvedConfig: ImageRendererConfig = {\n ...config,\n template: resolvedTemplate,\n };\n\n const playwright = await loadPlaywright();\n\n let browser: any;\n try {\n browser = await playwright.chromium.launch({\n headless: true,\n });\n } catch (error) {\n throw new BrowserLaunchError(\n 'Failed to launch Chromium. Ensure it is installed with: npx playwright install chromium',\n error instanceof Error ? error : undefined\n );\n }\n\n let staticRenderer: WoodStaticRenderer;\n if (resolvedConfig.staticRenderer) {\n staticRenderer = resolvedConfig.staticRenderer;\n } else if (resolvedConfig.viewsConfig && resolvedConfig.componentDir) {\n const { createWoodStaticRenderer } = await import('./static_renderer.js');\n staticRenderer = createWoodStaticRenderer({\n viewsConfig: resolvedConfig.viewsConfig,\n componentDir: resolvedConfig.componentDir,\n });\n } else {\n throw new Error(\n 'ImageRendererConfig requires either staticRenderer or both viewsConfig and componentDir'\n );\n }\n\n return new ImageRenderer(browser, staticRenderer, resolvedConfig);\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,417 @@
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 __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var automation_assertions_exports = {};
20
+ __export(automation_assertions_exports, {
21
+ automationAssertions: () => automationAssertions,
22
+ evenSpacing: () => evenSpacing,
23
+ evenSpacingRects: () => import_geometry.evenSpacing,
24
+ gaps: () => import_geometry.gaps,
25
+ hidden: () => hidden,
26
+ hitTestReachable: () => hitTestReachable,
27
+ insideViewport: () => insideViewport,
28
+ notClipped: () => notClipped,
29
+ notOverlapping: () => notOverlapping,
30
+ rectsOverlap: () => import_geometry.rectsOverlap,
31
+ sharedEdges: () => sharedEdges,
32
+ sharedRectEdges: () => import_geometry.sharedEdges,
33
+ stableAfterAnimation: () => stableAfterAnimation,
34
+ visible: () => visible
35
+ });
36
+ module.exports = __toCommonJS(automation_assertions_exports);
37
+ var import_geometry = require("./geometry.js");
38
+ function failure(message, details) {
39
+ return details ? { pass: false, message, details } : { pass: false, message };
40
+ }
41
+ function success(message, details) {
42
+ return details ? { pass: true, message, details } : { pass: true, message };
43
+ }
44
+ function errorDetails(error) {
45
+ return {
46
+ error: error instanceof Error ? error.message : String(error)
47
+ };
48
+ }
49
+ function locatorFor(page, target) {
50
+ return typeof target === "string" ? page.locator(target).first() : target.first();
51
+ }
52
+ function targetName(target) {
53
+ return typeof target === "string" ? `"${target}"` : "<locator>";
54
+ }
55
+ function isRectBox(target) {
56
+ const candidate = target;
57
+ return typeof candidate.top === "number" && typeof candidate.left === "number" && typeof candidate.right === "number" && typeof candidate.bottom === "number" && typeof candidate.width === "number" && typeof candidate.height === "number";
58
+ }
59
+ async function rectFor(page, target) {
60
+ if (isRectBox(target)) return target;
61
+ const box = await locatorFor(page, target).boundingBox();
62
+ if (!box) return null;
63
+ return {
64
+ top: box.y,
65
+ left: box.x,
66
+ right: box.x + box.width,
67
+ bottom: box.y + box.height,
68
+ width: box.width,
69
+ height: box.height
70
+ };
71
+ }
72
+ async function visible(page, target) {
73
+ try {
74
+ const pass = await locatorFor(page, target).isVisible();
75
+ return pass ? success(`Expected ${targetName(target)} to be visible.`) : failure(`Expected ${targetName(target)} to be visible, but it was hidden or missing.`);
76
+ } catch (error) {
77
+ return failure(
78
+ `Could not determine whether ${targetName(target)} is visible.`,
79
+ errorDetails(error)
80
+ );
81
+ }
82
+ }
83
+ async function hidden(page, target) {
84
+ try {
85
+ const pass = !await locatorFor(page, target).isVisible();
86
+ return pass ? success(`Expected ${targetName(target)} to be hidden.`) : failure(`Expected ${targetName(target)} to be hidden, but it was visible.`);
87
+ } catch (error) {
88
+ return failure(
89
+ `Could not determine whether ${targetName(target)} is hidden.`,
90
+ errorDetails(error)
91
+ );
92
+ }
93
+ }
94
+ async function insideViewport(page, target, options = {}) {
95
+ try {
96
+ const margin = options.margin ?? 0;
97
+ const rect = await rectFor(page, target);
98
+ if (!rect) {
99
+ return failure("Expected target to have a visible bounding box.", { margin });
100
+ }
101
+ const viewport = page.viewportSize() ?? await page.evaluate(() => ({
102
+ width: window.innerWidth,
103
+ height: window.innerHeight
104
+ }));
105
+ const pass = rect.left >= margin && rect.top >= margin && rect.right <= viewport.width - margin && rect.bottom <= viewport.height - margin;
106
+ const details = { rect, viewport, margin };
107
+ return pass ? success("Target is inside the viewport.", details) : failure("Target extends outside the viewport.", details);
108
+ } catch (error) {
109
+ return failure("Could not assert viewport bounds.", errorDetails(error));
110
+ }
111
+ }
112
+ async function notClipped(page, target) {
113
+ try {
114
+ const result = await locatorFor(page, target).evaluate((element) => {
115
+ const rect = element.getBoundingClientRect();
116
+ let parent = element.parentElement;
117
+ while (parent) {
118
+ const style = window.getComputedStyle(parent);
119
+ const clipsX = /(auto|hidden|scroll|clip)/.test(style.overflowX);
120
+ const clipsY = /(auto|hidden|scroll|clip)/.test(style.overflowY);
121
+ if (clipsX || clipsY) {
122
+ const parentRect = parent.getBoundingClientRect();
123
+ const clippedX = clipsX && (rect.left < parentRect.left || rect.right > parentRect.right);
124
+ const clippedY = clipsY && (rect.top < parentRect.top || rect.bottom > parentRect.bottom);
125
+ if (clippedX || clippedY) {
126
+ return {
127
+ pass: false,
128
+ ancestor: {
129
+ tag: parent.tagName,
130
+ id: parent.id || null,
131
+ classes: Array.from(parent.classList)
132
+ },
133
+ rect: {
134
+ top: rect.top,
135
+ left: rect.left,
136
+ right: rect.right,
137
+ bottom: rect.bottom,
138
+ width: rect.width,
139
+ height: rect.height
140
+ },
141
+ ancestorRect: {
142
+ top: parentRect.top,
143
+ left: parentRect.left,
144
+ right: parentRect.right,
145
+ bottom: parentRect.bottom,
146
+ width: parentRect.width,
147
+ height: parentRect.height
148
+ },
149
+ clippedX,
150
+ clippedY
151
+ };
152
+ }
153
+ }
154
+ parent = parent.parentElement;
155
+ }
156
+ return { pass: true };
157
+ });
158
+ return result.pass ? success(`Expected ${targetName(target)} not to be clipped.`) : failure(
159
+ `Expected ${targetName(target)} not to be clipped, but an overflow ancestor clips it.`,
160
+ result
161
+ );
162
+ } catch (error) {
163
+ return failure(
164
+ `Could not determine whether ${targetName(target)} is clipped.`,
165
+ errorDetails(error)
166
+ );
167
+ }
168
+ }
169
+ async function notOverlapping(page, firstTarget, secondTarget) {
170
+ try {
171
+ const [first, second] = await Promise.all([
172
+ rectFor(page, firstTarget),
173
+ rectFor(page, secondTarget)
174
+ ]);
175
+ if (!first || !second) {
176
+ return failure("Expected both targets to have visible bounding boxes.", {
177
+ first,
178
+ second
179
+ });
180
+ }
181
+ const overlap = (0, import_geometry.rectsOverlap)(first, second);
182
+ const details = { first, second };
183
+ return overlap ? failure("Expected targets not to overlap, but their border boxes intersect.", details) : success("Targets do not overlap.", details);
184
+ } catch (error) {
185
+ return failure("Could not compare target overlap.", errorDetails(error));
186
+ }
187
+ }
188
+ async function hitTestReachable(page, target) {
189
+ try {
190
+ const result = await locatorFor(page, target).evaluate((element) => {
191
+ if (typeof document.elementFromPoint !== "function") {
192
+ return {
193
+ supported: false,
194
+ capability: "DOM document.elementFromPoint"
195
+ };
196
+ }
197
+ const rect = element.getBoundingClientRect();
198
+ const point = {
199
+ x: rect.left + rect.width / 2,
200
+ y: rect.top + rect.height / 2
201
+ };
202
+ const hit = document.elementFromPoint(point.x, point.y);
203
+ const reachable = Boolean(
204
+ hit && (hit === element || element.contains(hit) || hit.contains(element))
205
+ );
206
+ return {
207
+ supported: true,
208
+ reachable,
209
+ point,
210
+ targetRect: {
211
+ top: rect.top,
212
+ left: rect.left,
213
+ right: rect.right,
214
+ bottom: rect.bottom,
215
+ width: rect.width,
216
+ height: rect.height
217
+ },
218
+ hit: hit ? {
219
+ tag: hit.tagName,
220
+ id: hit.id || null,
221
+ classes: Array.from(hit.classList)
222
+ } : null,
223
+ relationship: hit ? {
224
+ isTarget: hit === element,
225
+ isDescendant: element.contains(hit),
226
+ isAncestor: hit.contains(element)
227
+ } : null
228
+ };
229
+ });
230
+ if (!result.supported) {
231
+ return failure(
232
+ "Hit testing is unsupported on this page surface.",
233
+ { capability: result.capability }
234
+ );
235
+ }
236
+ return result.reachable ? success(`Center of ${targetName(target)} is hit-test reachable.`, result) : failure(
237
+ `Center of ${targetName(target)} is covered by a foreign element.`,
238
+ result
239
+ );
240
+ } catch (error) {
241
+ return failure(
242
+ `Could not hit-test ${targetName(target)}.`,
243
+ errorDetails(error)
244
+ );
245
+ }
246
+ }
247
+ async function sharedEdgesOnPage(page, targets, edge, options) {
248
+ try {
249
+ const rects = await Promise.all(targets.map((target) => rectFor(page, target)));
250
+ if (rects.some((rect) => rect === null)) {
251
+ return failure("Expected every target to have a visible bounding box.", {
252
+ missingIndices: rects.map((rect, index) => rect === null ? index : -1).filter((index) => index >= 0)
253
+ });
254
+ }
255
+ return (0, import_geometry.sharedEdges)(rects, edge, options);
256
+ } catch (error) {
257
+ return failure("Could not compare target edges.", errorDetails(error));
258
+ }
259
+ }
260
+ function sharedEdges(pageOrRects, targetsOrEdge, edgeOrOptions = {}, options = {}) {
261
+ if (Array.isArray(pageOrRects)) {
262
+ return (0, import_geometry.sharedEdges)(
263
+ pageOrRects,
264
+ targetsOrEdge,
265
+ edgeOrOptions
266
+ );
267
+ }
268
+ return sharedEdgesOnPage(
269
+ pageOrRects,
270
+ targetsOrEdge,
271
+ edgeOrOptions,
272
+ options
273
+ );
274
+ }
275
+ async function evenSpacingOnPage(page, targets, axis, options) {
276
+ try {
277
+ const rects = await Promise.all(targets.map((target) => rectFor(page, target)));
278
+ if (rects.some((rect) => rect === null)) {
279
+ return failure("Expected every target to have a visible bounding box.", {
280
+ missingIndices: rects.map((rect, index) => rect === null ? index : -1).filter((index) => index >= 0)
281
+ });
282
+ }
283
+ return (0, import_geometry.evenSpacing)(rects, axis, options);
284
+ } catch (error) {
285
+ return failure("Could not compare target spacing.", errorDetails(error));
286
+ }
287
+ }
288
+ function evenSpacing(pageOrRects, targetsOrAxis, axisOrOptions = {}, options = {}) {
289
+ if (Array.isArray(pageOrRects)) {
290
+ return (0, import_geometry.evenSpacing)(
291
+ pageOrRects,
292
+ targetsOrAxis,
293
+ axisOrOptions
294
+ );
295
+ }
296
+ return evenSpacingOnPage(
297
+ pageOrRects,
298
+ targetsOrAxis,
299
+ axisOrOptions,
300
+ options
301
+ );
302
+ }
303
+ async function stableAfterAnimation(page, target, options = {}) {
304
+ const frameCount = options.frameCount ?? 3;
305
+ const tolerance = options.tolerance ?? 0;
306
+ const timeoutMs = options.timeoutMs ?? 2e3;
307
+ if (!Number.isInteger(frameCount) || frameCount < 1) {
308
+ return failure("frameCount must be a positive integer.", { frameCount });
309
+ }
310
+ try {
311
+ const result = await locatorFor(page, target).evaluate(
312
+ async (element, input) => {
313
+ if (typeof window.requestAnimationFrame !== "function") {
314
+ return {
315
+ supported: false,
316
+ capability: "DOM window.requestAnimationFrame"
317
+ };
318
+ }
319
+ const read = () => {
320
+ const rect = element.getBoundingClientRect();
321
+ return {
322
+ top: rect.top,
323
+ left: rect.left,
324
+ right: rect.right,
325
+ bottom: rect.bottom,
326
+ width: rect.width,
327
+ height: rect.height
328
+ };
329
+ };
330
+ const samples = [read()];
331
+ let timedOut = false;
332
+ const timeout = window.setTimeout(() => {
333
+ timedOut = true;
334
+ }, input.timeoutMs);
335
+ for (let index = 0; index < input.frameCount && !timedOut; index += 1) {
336
+ await new Promise((resolve) => {
337
+ window.requestAnimationFrame(() => resolve());
338
+ });
339
+ samples.push(read());
340
+ }
341
+ window.clearTimeout(timeout);
342
+ if (timedOut) {
343
+ return { supported: true, timedOut: true, samples };
344
+ }
345
+ const first = samples[0];
346
+ const keys = ["top", "left", "right", "bottom", "width", "height"];
347
+ let maximumDelta = 0;
348
+ for (const sample of samples.slice(1)) {
349
+ for (const key of keys) {
350
+ maximumDelta = Math.max(maximumDelta, Math.abs(sample[key] - first[key]));
351
+ }
352
+ }
353
+ return {
354
+ supported: true,
355
+ timedOut: false,
356
+ stable: maximumDelta <= input.tolerance,
357
+ maximumDelta,
358
+ samples
359
+ };
360
+ },
361
+ { frameCount, tolerance, timeoutMs }
362
+ );
363
+ if (!result.supported) {
364
+ return failure(
365
+ "Animation stability sampling is unsupported on this page surface.",
366
+ { capability: result.capability }
367
+ );
368
+ }
369
+ if (result.timedOut) {
370
+ return failure(
371
+ `Animation stability sampling timed out after ${timeoutMs}ms.`,
372
+ result
373
+ );
374
+ }
375
+ return result.stable ? success(
376
+ `Bounding box stayed stable across ${frameCount} animation frames.`,
377
+ result
378
+ ) : failure(
379
+ `Bounding box changed across ${frameCount} animation frames.`,
380
+ result
381
+ );
382
+ } catch (error) {
383
+ return failure(
384
+ `Could not sample animation stability for ${targetName(target)}.`,
385
+ errorDetails(error)
386
+ );
387
+ }
388
+ }
389
+ const automationAssertions = {
390
+ visible,
391
+ hidden,
392
+ insideViewport,
393
+ notClipped,
394
+ notOverlapping,
395
+ hitTestReachable,
396
+ sharedEdges,
397
+ evenSpacing,
398
+ stableAfterAnimation
399
+ };
400
+ // Annotate the CommonJS export names for ESM import in node:
401
+ 0 && (module.exports = {
402
+ automationAssertions,
403
+ evenSpacing,
404
+ evenSpacingRects,
405
+ gaps,
406
+ hidden,
407
+ hitTestReachable,
408
+ insideViewport,
409
+ notClipped,
410
+ notOverlapping,
411
+ rectsOverlap,
412
+ sharedEdges,
413
+ sharedRectEdges,
414
+ stableAfterAnimation,
415
+ visible
416
+ });
417
+ //# sourceMappingURL=automation_assertions.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/testing/automation_assertions.ts"],"sourcesContent":["import type { Locator, Page } from 'playwright';\nimport {\n evenSpacing as evenSpacingRects,\n gaps,\n rectsOverlap,\n sharedEdges as sharedRectEdges,\n type GeometryVerdict,\n type RectAxis,\n type RectBox,\n type RectEdge,\n} from './geometry.js';\n\nexport {\n gaps,\n rectsOverlap,\n evenSpacingRects,\n sharedRectEdges,\n};\nexport type {\n GeometryVerdict,\n RectAxis,\n RectBox,\n RectEdge,\n};\n\nexport interface AssertionVerdict {\n pass: boolean;\n message: string;\n details?: Record<string, unknown>;\n}\n\nexport type AutomationTarget = string | Locator;\nexport type AutomationRectTarget = AutomationTarget | RectBox;\n\nfunction failure(\n message: string,\n details?: Record<string, unknown>,\n): AssertionVerdict {\n return details ? { pass: false, message, details } : { pass: false, message };\n}\n\nfunction success(\n message: string,\n details?: Record<string, unknown>,\n): AssertionVerdict {\n return details ? { pass: true, message, details } : { pass: true, message };\n}\n\nfunction errorDetails(error: unknown): Record<string, unknown> {\n return {\n error: error instanceof Error ? error.message : String(error),\n };\n}\n\nfunction locatorFor(page: Page, target: AutomationTarget): Locator {\n return typeof target === 'string' ? page.locator(target).first() : target.first();\n}\n\nfunction targetName(target: AutomationTarget): string {\n return typeof target === 'string' ? `\"${target}\"` : '<locator>';\n}\n\nfunction isRectBox(target: AutomationRectTarget): target is RectBox {\n const candidate = target as Partial<RectBox>;\n return typeof candidate.top === 'number'\n && typeof candidate.left === 'number'\n && typeof candidate.right === 'number'\n && typeof candidate.bottom === 'number'\n && typeof candidate.width === 'number'\n && typeof candidate.height === 'number';\n}\n\nasync function rectFor(\n page: Page,\n target: AutomationRectTarget,\n): Promise<RectBox | null> {\n if (isRectBox(target)) return target;\n const box = await locatorFor(page, target).boundingBox();\n if (!box) return null;\n return {\n top: box.y,\n left: box.x,\n right: box.x + box.width,\n bottom: box.y + box.height,\n width: box.width,\n height: box.height,\n };\n}\n\nexport async function visible(\n page: Page,\n target: AutomationTarget,\n): Promise<AssertionVerdict> {\n try {\n const pass = await locatorFor(page, target).isVisible();\n return pass\n ? success(`Expected ${targetName(target)} to be visible.`)\n : failure(`Expected ${targetName(target)} to be visible, but it was hidden or missing.`);\n } catch (error) {\n return failure(\n `Could not determine whether ${targetName(target)} is visible.`,\n errorDetails(error),\n );\n }\n}\n\nexport async function hidden(\n page: Page,\n target: AutomationTarget,\n): Promise<AssertionVerdict> {\n try {\n const pass = !(await locatorFor(page, target).isVisible());\n return pass\n ? success(`Expected ${targetName(target)} to be hidden.`)\n : failure(`Expected ${targetName(target)} to be hidden, but it was visible.`);\n } catch (error) {\n return failure(\n `Could not determine whether ${targetName(target)} is hidden.`,\n errorDetails(error),\n );\n }\n}\n\nexport async function insideViewport(\n page: Page,\n target: AutomationRectTarget,\n options: { margin?: number } = {},\n): Promise<AssertionVerdict> {\n try {\n const margin = options.margin ?? 0;\n const rect = await rectFor(page, target);\n if (!rect) {\n return failure('Expected target to have a visible bounding box.', { margin });\n }\n const viewport = page.viewportSize() ?? await page.evaluate(() => ({\n width: window.innerWidth,\n height: window.innerHeight,\n }));\n const pass = rect.left >= margin\n && rect.top >= margin\n && rect.right <= viewport.width - margin\n && rect.bottom <= viewport.height - margin;\n const details = { rect, viewport, margin };\n return pass\n ? success('Target is inside the viewport.', details)\n : failure('Target extends outside the viewport.', details);\n } catch (error) {\n return failure('Could not assert viewport bounds.', errorDetails(error));\n }\n}\n\nexport async function notClipped(\n page: Page,\n target: AutomationTarget,\n): Promise<AssertionVerdict> {\n try {\n const result = await locatorFor(page, target).evaluate((element: Element) => {\n const rect = element.getBoundingClientRect();\n let parent = element.parentElement;\n while (parent) {\n const style = window.getComputedStyle(parent);\n const clipsX = /(auto|hidden|scroll|clip)/.test(style.overflowX);\n const clipsY = /(auto|hidden|scroll|clip)/.test(style.overflowY);\n if (clipsX || clipsY) {\n const parentRect = parent.getBoundingClientRect();\n const clippedX = clipsX\n && (rect.left < parentRect.left || rect.right > parentRect.right);\n const clippedY = clipsY\n && (rect.top < parentRect.top || rect.bottom > parentRect.bottom);\n if (clippedX || clippedY) {\n return {\n pass: false,\n ancestor: {\n tag: parent.tagName,\n id: parent.id || null,\n classes: Array.from(parent.classList),\n },\n rect: {\n top: rect.top,\n left: rect.left,\n right: rect.right,\n bottom: rect.bottom,\n width: rect.width,\n height: rect.height,\n },\n ancestorRect: {\n top: parentRect.top,\n left: parentRect.left,\n right: parentRect.right,\n bottom: parentRect.bottom,\n width: parentRect.width,\n height: parentRect.height,\n },\n clippedX,\n clippedY,\n };\n }\n }\n parent = parent.parentElement;\n }\n return { pass: true };\n });\n\n return result.pass\n ? success(`Expected ${targetName(target)} not to be clipped.`)\n : failure(\n `Expected ${targetName(target)} not to be clipped, but an overflow ancestor clips it.`,\n result,\n );\n } catch (error) {\n return failure(\n `Could not determine whether ${targetName(target)} is clipped.`,\n errorDetails(error),\n );\n }\n}\n\nexport async function notOverlapping(\n page: Page,\n firstTarget: AutomationRectTarget,\n secondTarget: AutomationRectTarget,\n): Promise<AssertionVerdict> {\n try {\n const [first, second] = await Promise.all([\n rectFor(page, firstTarget),\n rectFor(page, secondTarget),\n ]);\n if (!first || !second) {\n return failure('Expected both targets to have visible bounding boxes.', {\n first,\n second,\n });\n }\n const overlap = rectsOverlap(first, second);\n const details = { first, second };\n return overlap\n ? failure('Expected targets not to overlap, but their border boxes intersect.', details)\n : success('Targets do not overlap.', details);\n } catch (error) {\n return failure('Could not compare target overlap.', errorDetails(error));\n }\n}\n\nexport async function hitTestReachable(\n page: Page,\n target: AutomationTarget,\n): Promise<AssertionVerdict> {\n try {\n const result = await locatorFor(page, target).evaluate((element: Element) => {\n if (typeof document.elementFromPoint !== 'function') {\n return {\n supported: false as const,\n capability: 'DOM document.elementFromPoint',\n };\n }\n const rect = element.getBoundingClientRect();\n const point = {\n x: rect.left + rect.width / 2,\n y: rect.top + rect.height / 2,\n };\n const hit = document.elementFromPoint(point.x, point.y);\n const reachable = Boolean(\n hit\n && (hit === element || element.contains(hit) || hit.contains(element)),\n );\n return {\n supported: true as const,\n reachable,\n point,\n targetRect: {\n top: rect.top,\n left: rect.left,\n right: rect.right,\n bottom: rect.bottom,\n width: rect.width,\n height: rect.height,\n },\n hit: hit ? {\n tag: hit.tagName,\n id: hit.id || null,\n classes: Array.from(hit.classList),\n } : null,\n relationship: hit ? {\n isTarget: hit === element,\n isDescendant: element.contains(hit),\n isAncestor: hit.contains(element),\n } : null,\n };\n });\n\n if (!result.supported) {\n return failure(\n 'Hit testing is unsupported on this page surface.',\n { capability: result.capability },\n );\n }\n return result.reachable\n ? success(`Center of ${targetName(target)} is hit-test reachable.`, result)\n : failure(\n `Center of ${targetName(target)} is covered by a foreign element.`,\n result,\n );\n } catch (error) {\n return failure(\n `Could not hit-test ${targetName(target)}.`,\n errorDetails(error),\n );\n }\n}\n\ntype GeometryOptions = { tolerance?: number };\n\nasync function sharedEdgesOnPage(\n page: Page,\n targets: readonly AutomationRectTarget[],\n edge: RectEdge,\n options: GeometryOptions,\n): Promise<AssertionVerdict> {\n try {\n const rects = await Promise.all(targets.map((target) => rectFor(page, target)));\n if (rects.some((rect) => rect === null)) {\n return failure('Expected every target to have a visible bounding box.', {\n missingIndices: rects\n .map((rect, index) => rect === null ? index : -1)\n .filter((index) => index >= 0),\n });\n }\n return sharedRectEdges(rects as RectBox[], edge, options);\n } catch (error) {\n return failure('Could not compare target edges.', errorDetails(error));\n }\n}\n\nexport function sharedEdges(\n rects: readonly RectBox[],\n edge: RectEdge,\n options?: GeometryOptions,\n): GeometryVerdict;\nexport function sharedEdges(\n page: Page,\n targets: readonly AutomationRectTarget[],\n edge: RectEdge,\n options?: GeometryOptions,\n): Promise<AssertionVerdict>;\nexport function sharedEdges(\n pageOrRects: Page | readonly RectBox[],\n targetsOrEdge: readonly AutomationRectTarget[] | RectEdge,\n edgeOrOptions: RectEdge | GeometryOptions = {},\n options: GeometryOptions = {},\n): GeometryVerdict | Promise<AssertionVerdict> {\n if (Array.isArray(pageOrRects)) {\n return sharedRectEdges(\n pageOrRects,\n targetsOrEdge as RectEdge,\n edgeOrOptions as GeometryOptions,\n );\n }\n return sharedEdgesOnPage(\n pageOrRects as Page,\n targetsOrEdge as readonly AutomationRectTarget[],\n edgeOrOptions as RectEdge,\n options,\n );\n}\n\nasync function evenSpacingOnPage(\n page: Page,\n targets: readonly AutomationRectTarget[],\n axis: RectAxis,\n options: GeometryOptions,\n): Promise<AssertionVerdict> {\n try {\n const rects = await Promise.all(targets.map((target) => rectFor(page, target)));\n if (rects.some((rect) => rect === null)) {\n return failure('Expected every target to have a visible bounding box.', {\n missingIndices: rects\n .map((rect, index) => rect === null ? index : -1)\n .filter((index) => index >= 0),\n });\n }\n return evenSpacingRects(rects as RectBox[], axis, options);\n } catch (error) {\n return failure('Could not compare target spacing.', errorDetails(error));\n }\n}\n\nexport function evenSpacing(\n rects: readonly RectBox[],\n axis: RectAxis,\n options?: GeometryOptions,\n): GeometryVerdict;\nexport function evenSpacing(\n page: Page,\n targets: readonly AutomationRectTarget[],\n axis: RectAxis,\n options?: GeometryOptions,\n): Promise<AssertionVerdict>;\nexport function evenSpacing(\n pageOrRects: Page | readonly RectBox[],\n targetsOrAxis: readonly AutomationRectTarget[] | RectAxis,\n axisOrOptions: RectAxis | GeometryOptions = {},\n options: GeometryOptions = {},\n): GeometryVerdict | Promise<AssertionVerdict> {\n if (Array.isArray(pageOrRects)) {\n return evenSpacingRects(\n pageOrRects,\n targetsOrAxis as RectAxis,\n axisOrOptions as GeometryOptions,\n );\n }\n return evenSpacingOnPage(\n pageOrRects as Page,\n targetsOrAxis as readonly AutomationRectTarget[],\n axisOrOptions as RectAxis,\n options,\n );\n}\n\nexport async function stableAfterAnimation(\n page: Page,\n target: AutomationTarget,\n options: { frameCount?: number; tolerance?: number; timeoutMs?: number } = {},\n): Promise<AssertionVerdict> {\n const frameCount = options.frameCount ?? 3;\n const tolerance = options.tolerance ?? 0;\n const timeoutMs = options.timeoutMs ?? 2000;\n if (!Number.isInteger(frameCount) || frameCount < 1) {\n return failure('frameCount must be a positive integer.', { frameCount });\n }\n\n try {\n const result = await locatorFor(page, target).evaluate(\n async (element: Element, input: {\n frameCount: number;\n tolerance: number;\n timeoutMs: number;\n }) => {\n if (typeof window.requestAnimationFrame !== 'function') {\n return {\n supported: false as const,\n capability: 'DOM window.requestAnimationFrame',\n };\n }\n const read = () => {\n const rect = element.getBoundingClientRect();\n return {\n top: rect.top,\n left: rect.left,\n right: rect.right,\n bottom: rect.bottom,\n width: rect.width,\n height: rect.height,\n };\n };\n const samples = [read()];\n let timedOut = false;\n const timeout = window.setTimeout(() => {\n timedOut = true;\n }, input.timeoutMs);\n for (let index = 0; index < input.frameCount && !timedOut; index += 1) {\n await new Promise<void>((resolve) => {\n window.requestAnimationFrame(() => resolve());\n });\n samples.push(read());\n }\n window.clearTimeout(timeout);\n if (timedOut) {\n return { supported: true as const, timedOut: true, samples };\n }\n\n const first = samples[0];\n const keys = ['top', 'left', 'right', 'bottom', 'width', 'height'] as const;\n let maximumDelta = 0;\n for (const sample of samples.slice(1)) {\n for (const key of keys) {\n maximumDelta = Math.max(maximumDelta, Math.abs(sample[key] - first[key]));\n }\n }\n return {\n supported: true as const,\n timedOut: false,\n stable: maximumDelta <= input.tolerance,\n maximumDelta,\n samples,\n };\n },\n { frameCount, tolerance, timeoutMs },\n );\n\n if (!result.supported) {\n return failure(\n 'Animation stability sampling is unsupported on this page surface.',\n { capability: result.capability },\n );\n }\n if (result.timedOut) {\n return failure(\n `Animation stability sampling timed out after ${timeoutMs}ms.`,\n result,\n );\n }\n return result.stable\n ? success(\n `Bounding box stayed stable across ${frameCount} animation frames.`,\n result,\n )\n : failure(\n `Bounding box changed across ${frameCount} animation frames.`,\n result,\n );\n } catch (error) {\n return failure(\n `Could not sample animation stability for ${targetName(target)}.`,\n errorDetails(error),\n );\n }\n}\n\nexport const automationAssertions = {\n visible,\n hidden,\n insideViewport,\n notClipped,\n notOverlapping,\n hitTestReachable,\n sharedEdges,\n evenSpacing,\n stableAfterAnimation,\n};\n"],"mappings":"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","names":["evenSpacingRects","sharedRectEdges"]}
@@ -0,0 +1,44 @@
1
+ import { Locator, Page } from 'playwright';
2
+ import { RectBox, RectEdge, GeometryVerdict, RectAxis } from './geometry.cjs';
3
+ export { evenSpacing as evenSpacingRects, gaps, rectsOverlap, sharedEdges as sharedRectEdges } from './geometry.cjs';
4
+
5
+ interface AssertionVerdict {
6
+ pass: boolean;
7
+ message: string;
8
+ details?: Record<string, unknown>;
9
+ }
10
+ type AutomationTarget = string | Locator;
11
+ type AutomationRectTarget = AutomationTarget | RectBox;
12
+ declare function visible(page: Page, target: AutomationTarget): Promise<AssertionVerdict>;
13
+ declare function hidden(page: Page, target: AutomationTarget): Promise<AssertionVerdict>;
14
+ declare function insideViewport(page: Page, target: AutomationRectTarget, options?: {
15
+ margin?: number;
16
+ }): Promise<AssertionVerdict>;
17
+ declare function notClipped(page: Page, target: AutomationTarget): Promise<AssertionVerdict>;
18
+ declare function notOverlapping(page: Page, firstTarget: AutomationRectTarget, secondTarget: AutomationRectTarget): Promise<AssertionVerdict>;
19
+ declare function hitTestReachable(page: Page, target: AutomationTarget): Promise<AssertionVerdict>;
20
+ type GeometryOptions = {
21
+ tolerance?: number;
22
+ };
23
+ declare function sharedEdges(rects: readonly RectBox[], edge: RectEdge, options?: GeometryOptions): GeometryVerdict;
24
+ declare function sharedEdges(page: Page, targets: readonly AutomationRectTarget[], edge: RectEdge, options?: GeometryOptions): Promise<AssertionVerdict>;
25
+ declare function evenSpacing(rects: readonly RectBox[], axis: RectAxis, options?: GeometryOptions): GeometryVerdict;
26
+ declare function evenSpacing(page: Page, targets: readonly AutomationRectTarget[], axis: RectAxis, options?: GeometryOptions): Promise<AssertionVerdict>;
27
+ declare function stableAfterAnimation(page: Page, target: AutomationTarget, options?: {
28
+ frameCount?: number;
29
+ tolerance?: number;
30
+ timeoutMs?: number;
31
+ }): Promise<AssertionVerdict>;
32
+ declare const automationAssertions: {
33
+ visible: typeof visible;
34
+ hidden: typeof hidden;
35
+ insideViewport: typeof insideViewport;
36
+ notClipped: typeof notClipped;
37
+ notOverlapping: typeof notOverlapping;
38
+ hitTestReachable: typeof hitTestReachable;
39
+ sharedEdges: typeof sharedEdges;
40
+ evenSpacing: typeof evenSpacing;
41
+ stableAfterAnimation: typeof stableAfterAnimation;
42
+ };
43
+
44
+ export { type AssertionVerdict, type AutomationRectTarget, type AutomationTarget, GeometryVerdict, RectAxis, RectBox, RectEdge, automationAssertions, evenSpacing, hidden, hitTestReachable, insideViewport, notClipped, notOverlapping, sharedEdges, stableAfterAnimation, visible };
@@ -0,0 +1,44 @@
1
+ import { Locator, Page } from 'playwright';
2
+ import { RectBox, RectEdge, GeometryVerdict, RectAxis } from './geometry.js';
3
+ export { evenSpacing as evenSpacingRects, gaps, rectsOverlap, sharedEdges as sharedRectEdges } from './geometry.js';
4
+
5
+ interface AssertionVerdict {
6
+ pass: boolean;
7
+ message: string;
8
+ details?: Record<string, unknown>;
9
+ }
10
+ type AutomationTarget = string | Locator;
11
+ type AutomationRectTarget = AutomationTarget | RectBox;
12
+ declare function visible(page: Page, target: AutomationTarget): Promise<AssertionVerdict>;
13
+ declare function hidden(page: Page, target: AutomationTarget): Promise<AssertionVerdict>;
14
+ declare function insideViewport(page: Page, target: AutomationRectTarget, options?: {
15
+ margin?: number;
16
+ }): Promise<AssertionVerdict>;
17
+ declare function notClipped(page: Page, target: AutomationTarget): Promise<AssertionVerdict>;
18
+ declare function notOverlapping(page: Page, firstTarget: AutomationRectTarget, secondTarget: AutomationRectTarget): Promise<AssertionVerdict>;
19
+ declare function hitTestReachable(page: Page, target: AutomationTarget): Promise<AssertionVerdict>;
20
+ type GeometryOptions = {
21
+ tolerance?: number;
22
+ };
23
+ declare function sharedEdges(rects: readonly RectBox[], edge: RectEdge, options?: GeometryOptions): GeometryVerdict;
24
+ declare function sharedEdges(page: Page, targets: readonly AutomationRectTarget[], edge: RectEdge, options?: GeometryOptions): Promise<AssertionVerdict>;
25
+ declare function evenSpacing(rects: readonly RectBox[], axis: RectAxis, options?: GeometryOptions): GeometryVerdict;
26
+ declare function evenSpacing(page: Page, targets: readonly AutomationRectTarget[], axis: RectAxis, options?: GeometryOptions): Promise<AssertionVerdict>;
27
+ declare function stableAfterAnimation(page: Page, target: AutomationTarget, options?: {
28
+ frameCount?: number;
29
+ tolerance?: number;
30
+ timeoutMs?: number;
31
+ }): Promise<AssertionVerdict>;
32
+ declare const automationAssertions: {
33
+ visible: typeof visible;
34
+ hidden: typeof hidden;
35
+ insideViewport: typeof insideViewport;
36
+ notClipped: typeof notClipped;
37
+ notOverlapping: typeof notOverlapping;
38
+ hitTestReachable: typeof hitTestReachable;
39
+ sharedEdges: typeof sharedEdges;
40
+ evenSpacing: typeof evenSpacing;
41
+ stableAfterAnimation: typeof stableAfterAnimation;
42
+ };
43
+
44
+ export { type AssertionVerdict, type AutomationRectTarget, type AutomationTarget, GeometryVerdict, RectAxis, RectBox, RectEdge, automationAssertions, evenSpacing, hidden, hitTestReachable, insideViewport, notClipped, notOverlapping, sharedEdges, stableAfterAnimation, visible };