@crvouga/atlas 0.4.0 → 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 (379) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/README.md +178 -617
  3. package/dist/bun/src/driver.d.ts +41 -7
  4. package/dist/bun/src/driver.js +47 -6
  5. package/dist/bun/src/index.d.ts +8 -0
  6. package/dist/bun/src/index.js +8 -0
  7. package/dist/core/src/cli.d.ts +14 -1
  8. package/dist/core/src/cli.js +30 -1
  9. package/dist/core/src/config.d.ts +70 -4
  10. package/dist/core/src/config.js +62 -3
  11. package/dist/core/src/events/cloudevents.d.ts +54 -9
  12. package/dist/core/src/events/cloudevents.js +60 -9
  13. package/dist/core/src/graph.d.ts +21 -0
  14. package/dist/core/src/graph.js +26 -0
  15. package/dist/core/src/index.d.ts +11 -0
  16. package/dist/core/src/index.js +11 -0
  17. package/dist/core/src/lint.d.ts +30 -0
  18. package/dist/core/src/lint.js +13 -0
  19. package/dist/core/src/plan.d.ts +39 -1
  20. package/dist/core/src/plan.js +28 -1
  21. package/dist/core/src/privacy.d.ts +29 -2
  22. package/dist/core/src/privacy.js +19 -2
  23. package/dist/core/src/report/formats.d.ts +34 -4
  24. package/dist/core/src/report/formats.js +24 -4
  25. package/dist/core/src/report/markdown.d.ts +15 -0
  26. package/dist/core/src/report/markdown.js +8 -0
  27. package/dist/core/src/run/clients.d.ts +44 -5
  28. package/dist/core/src/run/clients.js +46 -2
  29. package/dist/core/src/run/execute.d.ts +69 -16
  30. package/dist/core/src/run/execute.js +67 -16
  31. package/dist/core/src/run/frames.d.ts +13 -4
  32. package/dist/core/src/run/frames.js +19 -4
  33. package/dist/core/src/run/http.d.ts +34 -1
  34. package/dist/core/src/run/http.js +14 -1
  35. package/dist/core/src/run/types.d.ts +76 -3
  36. package/dist/core/src/run/types.js +19 -3
  37. package/dist/core/src/signals.d.ts +49 -5
  38. package/dist/core/src/signals.js +22 -5
  39. package/dist/core/src/spec/compose.d.ts +23 -1
  40. package/dist/core/src/spec/compose.js +10 -1
  41. package/dist/core/src/spec/index.d.ts +9 -1
  42. package/dist/core/src/spec/index.js +9 -1
  43. package/dist/core/src/spec/load.d.ts +22 -1
  44. package/dist/core/src/spec/load.js +31 -1
  45. package/dist/core/src/spec/parse.d.ts +16 -2
  46. package/dist/core/src/spec/parse.js +25 -2
  47. package/dist/core/src/spec/scxml.d.ts +25 -4
  48. package/dist/core/src/spec/scxml.js +36 -4
  49. package/dist/core/src/spec/types.d.ts +52 -1
  50. package/dist/core/src/spec/types.js +24 -0
  51. package/dist/detox/src/index.d.ts +54 -11
  52. package/dist/detox/src/index.js +45 -7
  53. package/dist/playwright/src/driver.d.ts +39 -3
  54. package/dist/playwright/src/driver.js +27 -3
  55. package/dist/playwright/src/index.d.ts +10 -0
  56. package/dist/playwright/src/index.js +10 -0
  57. package/dist/playwright/src/media.d.ts +50 -4
  58. package/dist/playwright/src/media.js +55 -4
  59. package/dist/playwright/src/signals.d.ts +44 -5
  60. package/dist/playwright/src/signals.js +29 -5
  61. package/dist/reports/src/attachment-files.d.ts +44 -0
  62. package/dist/reports/src/attachment-files.js +121 -0
  63. package/dist/reports/src/attachment-response.d.ts +31 -0
  64. package/dist/reports/src/attachment-response.js +55 -0
  65. package/dist/reports/src/aws-credentials.d.ts +48 -0
  66. package/dist/reports/src/aws-credentials.js +221 -0
  67. package/dist/reports/src/browser-navigation.d.ts +14 -0
  68. package/dist/reports/src/browser-navigation.js +7 -0
  69. package/dist/reports/src/bundle.d.ts +34 -2
  70. package/dist/reports/src/bundle.js +38 -2
  71. package/dist/reports/src/catalog.d.ts +34 -3
  72. package/dist/reports/src/catalog.js +17 -3
  73. package/dist/reports/src/cli-stores.d.ts +36 -0
  74. package/dist/reports/src/cli-stores.js +73 -0
  75. package/dist/reports/src/clock.d.ts +7 -2
  76. package/dist/reports/src/clock.js +5 -2
  77. package/dist/reports/src/completion-order.d.ts +18 -5
  78. package/dist/reports/src/completion-order.js +18 -5
  79. package/dist/reports/src/compose.d.ts +80 -0
  80. package/dist/reports/src/compose.js +117 -0
  81. package/dist/reports/src/copy-store.d.ts +29 -0
  82. package/dist/reports/src/copy-store.js +52 -0
  83. package/dist/reports/src/directory-outline.d.ts +38 -0
  84. package/dist/reports/src/directory-outline.js +103 -0
  85. package/dist/reports/src/directory-store.d.ts +20 -0
  86. package/dist/reports/src/directory-store.js +166 -0
  87. package/dist/reports/src/doctor.d.ts +29 -0
  88. package/dist/reports/src/doctor.js +83 -0
  89. package/dist/reports/src/effective-delta.d.ts +34 -0
  90. package/dist/reports/src/effective-delta.js +25 -0
  91. package/dist/reports/src/evidence-detail.d.ts +64 -0
  92. package/dist/reports/src/evidence-detail.js +92 -0
  93. package/dist/reports/src/evidence-live.d.ts +35 -5
  94. package/dist/reports/src/evidence-live.js +18 -2
  95. package/dist/reports/src/evidence-types.d.ts +68 -1
  96. package/dist/reports/src/evidence-types.js +5 -1
  97. package/dist/reports/src/evidence-view.d.ts +43 -4
  98. package/dist/reports/src/evidence-view.js +13 -2
  99. package/dist/reports/src/explorer-types.d.ts +40 -3
  100. package/dist/reports/src/explorer-types.js +8 -0
  101. package/dist/reports/src/explorer-versions.d.ts +9 -1
  102. package/dist/reports/src/explorer-versions.js +18 -1
  103. package/dist/reports/src/export-evidence.d.ts +16 -1
  104. package/dist/reports/src/export-evidence.js +52 -1
  105. package/dist/reports/src/fetcher.d.ts +27 -3
  106. package/dist/reports/src/fetcher.js +11 -3
  107. package/dist/reports/src/format-date.d.ts +6 -0
  108. package/dist/reports/src/format-date.js +6 -0
  109. package/dist/reports/src/format.d.ts +16 -0
  110. package/dist/reports/src/format.js +10 -0
  111. package/dist/reports/src/frames.d.ts +36 -3
  112. package/dist/reports/src/frames.js +22 -3
  113. package/dist/reports/src/hash.d.ts +18 -0
  114. package/dist/reports/src/hash.js +13 -0
  115. package/dist/reports/src/host.d.ts +29 -0
  116. package/dist/reports/src/host.js +64 -0
  117. package/dist/reports/src/html-frame.d.ts +5 -6
  118. package/dist/reports/src/html-frame.js +12 -1
  119. package/dist/reports/src/http-store.d.ts +52 -0
  120. package/dist/reports/src/http-store.js +145 -0
  121. package/dist/reports/src/http.d.ts +7 -0
  122. package/dist/reports/src/http.js +6 -0
  123. package/dist/reports/src/ingest.d.ts +54 -0
  124. package/dist/reports/src/ingest.js +210 -0
  125. package/dist/reports/src/init.d.ts +40 -0
  126. package/dist/reports/src/init.js +364 -0
  127. package/dist/reports/src/junit.d.ts +33 -6
  128. package/dist/reports/src/junit.js +87 -21
  129. package/dist/reports/src/keyboard.d.ts +20 -0
  130. package/dist/reports/src/keyboard.js +11 -0
  131. package/dist/reports/src/keys.d.ts +21 -3
  132. package/dist/reports/src/keys.js +21 -3
  133. package/dist/reports/src/layer-axes.d.ts +35 -5
  134. package/dist/reports/src/layer-axes.js +25 -5
  135. package/dist/reports/src/layer-catalog.d.ts +28 -1
  136. package/dist/reports/src/layer-catalog.js +18 -1
  137. package/dist/reports/src/layer-merge.d.ts +98 -9
  138. package/dist/reports/src/layer-merge.js +147 -31
  139. package/dist/reports/src/layer-source.d.ts +18 -0
  140. package/dist/reports/src/layer-source.js +11 -0
  141. package/dist/reports/src/layer-store.d.ts +42 -0
  142. package/dist/reports/src/layer-store.js +63 -5
  143. package/dist/reports/src/layer-types.d.ts +32 -1
  144. package/dist/reports/src/layers-route.d.ts +47 -4
  145. package/dist/reports/src/layers-route.js +86 -7
  146. package/dist/reports/src/media-types.d.ts +11 -0
  147. package/dist/reports/src/media-types.js +22 -0
  148. package/dist/reports/src/namespace-guard.d.ts +10 -1
  149. package/dist/reports/src/namespace-guard.js +10 -1
  150. package/dist/reports/src/navigation.d.ts +12 -0
  151. package/dist/reports/src/navigation.js +7 -0
  152. package/dist/reports/src/object-io.d.ts +11 -4
  153. package/dist/reports/src/object-io.js +4 -4
  154. package/dist/reports/src/object-store-conformance.d.ts +27 -0
  155. package/dist/reports/src/object-store-conformance.js +87 -0
  156. package/dist/reports/src/object-store.d.ts +33 -24
  157. package/dist/reports/src/object-store.js +17 -24
  158. package/dist/reports/src/parse-with.d.ts +16 -0
  159. package/dist/reports/src/parse-with.js +14 -0
  160. package/dist/reports/src/performance-part.d.ts +25 -1
  161. package/dist/reports/src/performance-part.js +15 -1
  162. package/dist/reports/src/performance.d.ts +22 -2
  163. package/dist/reports/src/performance.js +12 -2
  164. package/dist/reports/src/persist.d.ts +12 -3
  165. package/dist/reports/src/persist.js +12 -3
  166. package/dist/reports/src/phone.d.ts +18 -1
  167. package/dist/reports/src/phone.js +18 -1
  168. package/dist/reports/src/protocol.d.ts +26 -4
  169. package/dist/reports/src/protocol.js +15 -4
  170. package/dist/reports/src/publication.d.ts +21 -1
  171. package/dist/reports/src/publication.js +21 -1
  172. package/dist/reports/src/publish-checks.d.ts +35 -0
  173. package/dist/reports/src/publish-checks.js +122 -0
  174. package/dist/reports/src/publish.d.ts +42 -9
  175. package/dist/reports/src/publish.js +36 -7
  176. package/dist/reports/src/read.d.ts +46 -16
  177. package/dist/reports/src/read.js +38 -14
  178. package/dist/reports/src/recording-bundle.d.ts +13 -2
  179. package/dist/reports/src/recording-bundle.js +4 -2
  180. package/dist/reports/src/recording-keys.d.ts +15 -1
  181. package/dist/reports/src/recording-keys.js +15 -1
  182. package/dist/reports/src/remote-report.d.ts +28 -7
  183. package/dist/reports/src/remote-report.js +15 -7
  184. package/dist/reports/src/report-cli.d.ts +51 -0
  185. package/dist/reports/src/report-cli.js +485 -0
  186. package/dist/reports/src/report-index.d.ts +99 -0
  187. package/dist/reports/src/report-index.js +337 -0
  188. package/dist/reports/src/report-loader.d.ts +10 -0
  189. package/dist/reports/src/report-loader.js +6 -0
  190. package/dist/reports/src/report-parts.d.ts +29 -3
  191. package/dist/reports/src/report-parts.js +37 -3
  192. package/dist/reports/src/report-status.d.ts +48 -0
  193. package/dist/reports/src/report-status.js +156 -0
  194. package/dist/reports/src/report-types.d.ts +73 -0
  195. package/dist/reports/src/report-types.js +3 -0
  196. package/dist/reports/src/reporter.d.ts +67 -0
  197. package/dist/reports/src/reporter.js +128 -0
  198. package/dist/reports/src/reports-explorer-route.d.ts +541 -0
  199. package/dist/reports/src/reports-explorer-route.js +11 -0
  200. package/dist/reports/src/reports-list-route.d.ts +9 -0
  201. package/dist/reports/src/reports-list-route.js +9 -0
  202. package/dist/reports/src/reports-route.d.ts +561 -22
  203. package/dist/reports/src/reports-route.js +11 -3
  204. package/dist/reports/src/reports-store.d.ts +19 -2
  205. package/dist/reports/src/reports-store.js +10 -2
  206. package/dist/reports/src/resilient-cache.d.ts +14 -1
  207. package/dist/reports/src/resilient-cache.js +8 -1
  208. package/dist/reports/src/retention.d.ts +17 -1
  209. package/dist/reports/src/retention.js +5 -1
  210. package/dist/reports/src/run-bundle.d.ts +63 -0
  211. package/dist/reports/src/run-bundle.js +159 -0
  212. package/dist/reports/src/s3-store.d.ts +79 -0
  213. package/dist/reports/src/s3-store.js +295 -0
  214. package/dist/reports/src/scenario.d.ts +14 -4
  215. package/dist/reports/src/scenario.js +5 -4
  216. package/dist/reports/src/sigv4.d.ts +72 -0
  217. package/dist/reports/src/sigv4.js +96 -0
  218. package/dist/reports/src/snapshot-bundle.d.ts +24 -1
  219. package/dist/reports/src/snapshot-bundle.js +27 -2
  220. package/dist/reports/src/snapshot-surface.d.ts +20 -9
  221. package/dist/reports/src/snapshot-surface.js +32 -19
  222. package/dist/reports/src/source-content.d.ts +23 -0
  223. package/dist/reports/src/source-content.js +30 -1
  224. package/dist/reports/src/source-entries.d.ts +13 -0
  225. package/dist/reports/src/source-entries.js +6 -0
  226. package/dist/reports/src/source-part.d.ts +15 -0
  227. package/dist/reports/src/source-part.js +8 -0
  228. package/dist/reports/src/source-reader.d.ts +11 -0
  229. package/dist/reports/src/source-reader.js +5 -0
  230. package/dist/reports/src/spec-evidence.d.ts +12 -2
  231. package/dist/reports/src/spec-evidence.js +6 -2
  232. package/dist/reports/src/spec-inventory.d.ts +15 -1
  233. package/dist/reports/src/spec-inventory.js +22 -1
  234. package/dist/reports/src/spec-link.d.ts +28 -0
  235. package/dist/reports/src/spec-link.js +70 -0
  236. package/dist/reports/src/spec-set.d.ts +63 -0
  237. package/dist/reports/src/spec-set.js +177 -0
  238. package/dist/reports/src/status.d.ts +10 -0
  239. package/dist/reports/src/status.js +5 -0
  240. package/dist/reports/src/store-prefix.d.ts +28 -0
  241. package/dist/reports/src/store-prefix.js +22 -0
  242. package/dist/reports/src/store-url.d.ts +89 -0
  243. package/dist/reports/src/store-url.js +160 -0
  244. package/dist/reports/src/test-catalog-entity.d.ts +11 -0
  245. package/dist/reports/src/test-catalog-entity.js +6 -0
  246. package/dist/reports/src/types.d.ts +6 -1
  247. package/dist/reports/src/use-report-nav.d.ts +35 -0
  248. package/dist/reports/src/use-report-nav.js +12 -0
  249. package/dist/schema/src/api.d.ts +799 -0
  250. package/dist/schema/src/api.js +201 -0
  251. package/dist/schema/src/cli-results.d.ts +210 -0
  252. package/dist/schema/src/cli-results.js +124 -0
  253. package/dist/schema/src/common.d.ts +53 -0
  254. package/dist/schema/src/common.js +42 -0
  255. package/dist/schema/src/index.d.ts +14 -0
  256. package/dist/schema/src/index.js +14 -0
  257. package/dist/schema/src/layer.d.ts +2273 -0
  258. package/dist/schema/src/layer.js +462 -0
  259. package/dist/schema/src/manifest.d.ts +95 -0
  260. package/dist/schema/src/manifest.js +84 -0
  261. package/dist/schema/src/report-sources.d.ts +28 -0
  262. package/dist/schema/src/report-sources.js +25 -0
  263. package/dist/schema/src/runs-index.d.ts +16 -0
  264. package/dist/schema/src/runs-index.js +15 -0
  265. package/dist/schema/src/server-config.d.ts +93 -0
  266. package/dist/schema/src/server-config.js +73 -0
  267. package/dist/schema/src/spec.d.ts +69 -0
  268. package/dist/schema/src/spec.js +58 -0
  269. package/dist/server/src/app.d.ts +62 -0
  270. package/dist/server/src/app.js +419 -0
  271. package/dist/server/src/auth.d.ts +41 -0
  272. package/dist/server/src/auth.js +59 -0
  273. package/dist/server/src/config.d.ts +83 -0
  274. package/dist/server/src/config.js +187 -0
  275. package/dist/server/src/dev.d.ts +12 -0
  276. package/dist/server/src/dev.js +80 -0
  277. package/dist/server/src/events.d.ts +29 -0
  278. package/dist/server/src/events.js +101 -0
  279. package/dist/server/src/host.d.ts +30 -0
  280. package/dist/server/src/host.js +115 -0
  281. package/dist/server/src/index.d.ts +16 -0
  282. package/dist/server/src/index.js +16 -0
  283. package/dist/server/src/llms.d.ts +19 -0
  284. package/dist/server/src/llms.js +63 -0
  285. package/dist/server/src/main.d.ts +30 -0
  286. package/dist/server/src/main.js +112 -0
  287. package/dist/server/src/openapi.d.ts +59 -0
  288. package/dist/server/src/openapi.js +374 -0
  289. package/dist/server/src/problem.d.ts +8 -0
  290. package/dist/server/src/problem.js +39 -0
  291. package/dist/server/src/site.d.ts +13 -0
  292. package/dist/server/src/site.js +43 -0
  293. package/dist/server/src/store-api.d.ts +28 -0
  294. package/dist/server/src/store-api.js +159 -0
  295. package/dist/server/src/validate.d.ts +71 -0
  296. package/dist/server/src/validate.js +197 -0
  297. package/dist/vitest/src/index.d.ts +27 -5
  298. package/dist/vitest/src/index.js +18 -5
  299. package/dist/webdriver/src/driver.d.ts +63 -11
  300. package/dist/webdriver/src/driver.js +57 -6
  301. package/dist/webdriver/src/index.d.ts +8 -0
  302. package/dist/webdriver/src/index.js +1 -0
  303. package/dist/webdriver/src/protocol.d.ts +75 -6
  304. package/dist/webdriver/src/protocol.js +79 -6
  305. package/docs/agents.md +137 -0
  306. package/docs/deploying.md +345 -0
  307. package/docs/dogfooding.md +175 -0
  308. package/docs/extending.md +242 -0
  309. package/docs/integrating.md +485 -0
  310. package/docs/reference/bun.md +141 -0
  311. package/docs/reference/cli.md +146 -0
  312. package/docs/reference/core.md +2426 -0
  313. package/docs/reference/detox.md +150 -0
  314. package/docs/reference/http-api.md +303 -0
  315. package/docs/reference/playwright.md +303 -0
  316. package/docs/reference/reports.md +7098 -0
  317. package/docs/reference/schema.md +1651 -0
  318. package/docs/reference/server.md +685 -0
  319. package/docs/reference/vitest.md +45 -0
  320. package/docs/reference/webdriver.md +330 -0
  321. package/docs/report-backends.md +144 -0
  322. package/docs/report-contract.md +400 -0
  323. package/docs/reporting-issues.md +160 -0
  324. package/docs/server.md +285 -0
  325. package/docs/statecharts.md +641 -0
  326. package/llms-full.txt +3506 -0
  327. package/llms.txt +47 -0
  328. package/package.json +32 -4
  329. package/packages/core/README.md +2 -1
  330. package/packages/reports/README.md +65 -0
  331. package/packages/reports/STORAGE.md +4 -0
  332. package/packages/schema/README.md +14 -0
  333. package/packages/schema/schemas/check-detail.schema.json +1032 -0
  334. package/packages/schema/schemas/checks-result.schema.json +26 -0
  335. package/packages/schema/schemas/command-error.schema.json +35 -0
  336. package/packages/schema/schemas/doctor-result.schema.json +60 -0
  337. package/packages/schema/schemas/effective-delta.schema.json +490 -0
  338. package/packages/schema/schemas/effective-evidence.schema.json +471 -0
  339. package/packages/schema/schemas/evidence-page.schema.json +271 -0
  340. package/packages/schema/schemas/hello-event.schema.json +22 -0
  341. package/packages/schema/schemas/init-plan.schema.json +347 -0
  342. package/packages/schema/schemas/layer-rows.schema.json +199 -0
  343. package/packages/schema/schemas/layer.schema.json +2888 -0
  344. package/packages/schema/schemas/merge-result.schema.json +40 -0
  345. package/packages/schema/schemas/outline.schema.json +62 -0
  346. package/packages/schema/schemas/problem.schema.json +37 -0
  347. package/packages/schema/schemas/publish-checks.schema.json +1413 -0
  348. package/packages/schema/schemas/publish-result.schema.json +168 -0
  349. package/packages/schema/schemas/ready.schema.json +68 -0
  350. package/packages/schema/schemas/report-event.schema.json +100 -0
  351. package/packages/schema/schemas/report-status.schema.json +370 -0
  352. package/packages/schema/schemas/server-config.schema.json +194 -0
  353. package/packages/schema/schemas/server-info.schema.json +114 -0
  354. package/packages/schema/schemas/spec-set.schema.json +103 -0
  355. package/packages/schema/schemas/store-listing.schema.json +29 -0
  356. package/packages/schema/schemas/store-write-result.schema.json +28 -0
  357. package/packages/schema/schemas/stream-result.schema.json +59 -0
  358. package/packages/server/README.md +43 -0
  359. package/packages/server/openapi.json +6699 -0
  360. package/packages/visualizer/README.md +21 -0
  361. package/packages/visualizer/src/app/AppShell.tsx +9 -2
  362. package/packages/visualizer/src/app/report-sources.tsx +6 -4
  363. package/packages/visualizer/src/app/router.tsx +3 -3
  364. package/packages/visualizer/src/components/Header.module.css +35 -0
  365. package/packages/visualizer/src/components/Header.tsx +40 -3
  366. package/packages/visualizer/src/data/adapters/adapter.ts +5 -17
  367. package/packages/visualizer/src/data/adapters/index.ts +10 -1
  368. package/packages/visualizer/src/evidence/api.ts +14 -2
  369. package/packages/visualizer/src/evidence/artifacts.module.css +213 -0
  370. package/packages/visualizer/src/evidence/artifacts.tsx +272 -0
  371. package/packages/visualizer/src/evidence/check-detail.tsx +3 -1
  372. package/packages/visualizer/src/evidence/evidence-context.tsx +74 -12
  373. package/packages/visualizer/src/evidence/spec-page.tsx +23 -16
  374. package/packages/visualizer/src/find/Finder.tsx +1 -7
  375. package/packages/visualizer/src/find/open.ts +4 -0
  376. package/packages/visualizer/src/live/live-stream.ts +204 -0
  377. package/packages/visualizer/src/runtime.ts +19 -0
  378. package/packages/visualizer/vite/atlas-server-proxy.ts +36 -0
  379. package/packages/visualizer/vite.config.ts +11 -3
@@ -4,7 +4,7 @@ function asTransition(t) {
4
4
  return target ? { target: `#${target}` } : undefined;
5
5
  }
6
6
  /**
7
- * Inline every child chart where its parent invokes it, so XState's graph traversal (which cannot
7
+ * Inlines every child chart where its parent invokes it, so XState's graph traversal (which cannot
8
8
  * enter an invoked actor) walks straight through. Supports:
9
9
  *
10
10
  * - XState `invoke: { src, id, onDone }` and SCXML `<invoke>` + `done.invoke.<id>`;
@@ -13,6 +13,15 @@ function asTransition(t) {
13
13
  *
14
14
  * A child's final states stay as states (they keep their screenshots and checks) but stop being
15
15
  * final: each takes the parent's transition for its hand-off event.
16
+ *
17
+ * Every state without an `id` gets its own name as `id`. A child's `initial` replaces the host
18
+ * state's `initial`, and the host's transitions that consumed a hand-off event are removed from it.
19
+ *
20
+ * @throws Error when the root chart is not loaded, an invoked chart is not loaded, charts invoke
21
+ * each other in a cycle, or a child's final state has no matching transition (or `onDone`) in the parent.
22
+ *
23
+ * @example
24
+ * const { machine, handOffs } = composeCharts(loadSpecDirectory('./specs'));
16
25
  */
17
26
  export function composeCharts(bundle) {
18
27
  const byId = new Map(bundle.charts.map((c) => [c.machine.id, c.machine]));
@@ -1,4 +1,12 @@
1
- /** Browser-safe: parsing, SCXML conversion and composition, with no Node built-ins. */
1
+ /**
2
+ * @module Spec entry point (browser-safe)
3
+ *
4
+ * Re-exports the parts of the spec layer that need no Node built-ins: the spec types, chart and
5
+ * journey parsing, SCXML conversion and static composition. `loadSpecDirectory` (which reads the
6
+ * file system) is deliberately not here; import it from the package root.
7
+ *
8
+ * @see docs/statecharts.md
9
+ */
2
10
  export * from './types.js';
3
11
  export { parseChart, parseJourneys } from './parse.js';
4
12
  export { scxmlToMachine, machineToScxml, scxmlToken, ATLAS_NS } from './scxml.js';
@@ -1,4 +1,12 @@
1
- /** Browser-safe: parsing, SCXML conversion and composition, with no Node built-ins. */
1
+ /**
2
+ * @module Spec entry point (browser-safe)
3
+ *
4
+ * Re-exports the parts of the spec layer that need no Node built-ins: the spec types, chart and
5
+ * journey parsing, SCXML conversion and static composition. `loadSpecDirectory` (which reads the
6
+ * file system) is deliberately not here; import it from the package root.
7
+ *
8
+ * @see docs/statecharts.md
9
+ */
2
10
  export * from './types.js';
3
11
  export { parseChart, parseJourneys } from './parse.js';
4
12
  export { scxmlToMachine, machineToScxml, scxmlToken, ATLAS_NS } from './scxml.js';
@@ -3,6 +3,27 @@ import { parseChart, parseJourneys } from './parse.js';
3
3
  export { parseChart, parseJourneys };
4
4
  /** The ids of the charts a machine composes, by `invoke` or the legacy `meta.childMachine`. */
5
5
  export declare function childChartIds(machine: MachineConfig): Set<string>;
6
+ /**
7
+ * Assembles a bundle from already-parsed charts and journeys, choosing the root chart: the first
8
+ * chart (in the order given) that no other chart invokes, or the first chart when every chart is
9
+ * invoked by another (a cycle, which `composeCharts` later rejects).
10
+ *
11
+ * @throws Error when `charts` is empty.
12
+ */
6
13
  export declare function bundleOf(directory: string, charts: Chart[], journeys: Journey[]): SpecBundle;
7
- /** Load every chart and journeys file directly inside `directory`. */
14
+ /**
15
+ * Loads every chart and journeys file directly inside `directory` into a bundle.
16
+ *
17
+ * Chart files are `*.scxml`, `*.machine.json` and `*.machine.yaml`/`.yml`; journeys files are
18
+ * `journeys.yaml`/`.yml`/`.json`. When two files declare the same chart id the first wins, in the
19
+ * order SCXML, then YAML, then JSON, then by file name, so the result does not depend on directory
20
+ * order.
21
+ *
22
+ * @throws Error when the directory is missing, a file does not parse, or no chart is found.
23
+ * @see docs/statecharts.md
24
+ *
25
+ * @example
26
+ * const bundle = loadSpecDirectory('./specs');
27
+ * bundle.root; // the id of the chart no other chart invokes
28
+ */
8
29
  export declare function loadSpecDirectory(directory: string): SpecBundle;
@@ -1,3 +1,12 @@
1
+ /**
2
+ * @module Spec directory loader
3
+ *
4
+ * Reads a specs directory from disk into a `SpecBundle`: every chart file and journeys file directly
5
+ * inside it (no recursion), and works out the root chart. Node only. Parsing itself lives in `./parse`;
6
+ * loading throws on the first malformed file rather than skipping it.
7
+ *
8
+ * @see docs/statecharts.md
9
+ */
1
10
  import { existsSync, readdirSync, readFileSync } from 'node:fs';
2
11
  import path from 'node:path';
3
12
  import { parseChart, parseJourneys } from './parse.js';
@@ -16,6 +25,13 @@ export function childChartIds(machine) {
16
25
  }
17
26
  return ids;
18
27
  }
28
+ /**
29
+ * Assembles a bundle from already-parsed charts and journeys, choosing the root chart: the first
30
+ * chart (in the order given) that no other chart invokes, or the first chart when every chart is
31
+ * invoked by another (a cycle, which `composeCharts` later rejects).
32
+ *
33
+ * @throws Error when `charts` is empty.
34
+ */
19
35
  export function bundleOf(directory, charts, journeys) {
20
36
  const invoked = new Set(charts.flatMap((c) => [...childChartIds(c.machine)]));
21
37
  const roots = charts.filter((c) => !invoked.has(c.machine.id));
@@ -24,7 +40,21 @@ export function bundleOf(directory, charts, journeys) {
24
40
  throw new Error(`No statechart found in ${directory}`);
25
41
  return { directory, charts, journeys, root };
26
42
  }
27
- /** Load every chart and journeys file directly inside `directory`. */
43
+ /**
44
+ * Loads every chart and journeys file directly inside `directory` into a bundle.
45
+ *
46
+ * Chart files are `*.scxml`, `*.machine.json` and `*.machine.yaml`/`.yml`; journeys files are
47
+ * `journeys.yaml`/`.yml`/`.json`. When two files declare the same chart id the first wins, in the
48
+ * order SCXML, then YAML, then JSON, then by file name, so the result does not depend on directory
49
+ * order.
50
+ *
51
+ * @throws Error when the directory is missing, a file does not parse, or no chart is found.
52
+ * @see docs/statecharts.md
53
+ *
54
+ * @example
55
+ * const bundle = loadSpecDirectory('./specs');
56
+ * bundle.root; // the id of the chart no other chart invokes
57
+ */
28
58
  export function loadSpecDirectory(directory) {
29
59
  if (!existsSync(directory))
30
60
  throw new Error(`Spec directory not found: ${directory}`);
@@ -1,5 +1,19 @@
1
1
  import type { Chart, Journey } from './types.js';
2
- /** Parse one chart from its text, by file name: SCXML or XState config in JSON or YAML. */
2
+ /**
3
+ * Parses one chart from its text. The file name picks the format: `.scxml` is SCXML (the machine id
4
+ * falls back to the file's base name), `.json` is an XState config, anything else is read as YAML.
5
+ *
6
+ * @param file the file name, relative to the specs directory; stored as `Chart.file`.
7
+ * @param text the file contents.
8
+ * @throws Error when an XState config is not an object with a string `id` and a `states` object, or
9
+ * when the text is not valid JSON/YAML/SCXML.
10
+ */
3
11
  export declare function parseChart(file: string, text: string): Chart;
4
- /** Parse a journeys file: `{ journeys: { <name>: { description, events, endsIn } } }`. */
12
+ /**
13
+ * Parses a journeys file of the form `{ journeys: { <name>: { description, events, endsIn } } }`
14
+ * (JSON when the name ends in `.json`, otherwise YAML). Journeys come back in declaration order.
15
+ * `description` defaults to `''` and `endsIn` to `[]`; events are coerced to strings.
16
+ *
17
+ * @throws Error when there is no `journeys` map, or a journey has no `events` list.
18
+ */
5
19
  export declare function parseJourneys(file: string, text: string): Journey[];
@@ -1,9 +1,26 @@
1
+ /**
2
+ * @module Chart and journeys parsers
3
+ *
4
+ * Turns the text of one spec file into a `Chart` or a list of `Journey`. Pure functions of their
5
+ * input (no file access), so they run in a browser too. They check only the shape that later stages
6
+ * rely on; whether the chart is executable is the linter's job.
7
+ *
8
+ * @see docs/statecharts.md
9
+ */
1
10
  import YAML from 'yaml';
2
11
  import { scxmlToMachine } from './scxml.js';
3
12
  function isRecord(value) {
4
13
  return value !== null && typeof value === 'object' && !Array.isArray(value);
5
14
  }
6
- /** Parse one chart from its text, by file name: SCXML or XState config in JSON or YAML. */
15
+ /**
16
+ * Parses one chart from its text. The file name picks the format: `.scxml` is SCXML (the machine id
17
+ * falls back to the file's base name), `.json` is an XState config, anything else is read as YAML.
18
+ *
19
+ * @param file the file name, relative to the specs directory; stored as `Chart.file`.
20
+ * @param text the file contents.
21
+ * @throws Error when an XState config is not an object with a string `id` and a `states` object, or
22
+ * when the text is not valid JSON/YAML/SCXML.
23
+ */
7
24
  export function parseChart(file, text) {
8
25
  if (file.endsWith('.scxml')) {
9
26
  return { file, format: 'scxml', machine: scxmlToMachine(text, file.replace(/^.*[\\/]/, '').replace(/\.scxml$/, '')) };
@@ -14,7 +31,13 @@ export function parseChart(file, text) {
14
31
  }
15
32
  return { file, format: 'xstate', machine: value };
16
33
  }
17
- /** Parse a journeys file: `{ journeys: { <name>: { description, events, endsIn } } }`. */
34
+ /**
35
+ * Parses a journeys file of the form `{ journeys: { <name>: { description, events, endsIn } } }`
36
+ * (JSON when the name ends in `.json`, otherwise YAML). Journeys come back in declaration order.
37
+ * `description` defaults to `''` and `endsIn` to `[]`; events are coerced to strings.
38
+ *
39
+ * @throws Error when there is no `journeys` map, or a journey has no `events` list.
40
+ */
18
41
  export function parseJourneys(file, text) {
19
42
  const value = file.endsWith('.json') ? JSON.parse(text) : YAML.parse(text);
20
43
  if (!isRecord(value) || !isRecord(value['journeys']))
@@ -1,6 +1,8 @@
1
1
  import type { MachineConfig } from './types.js';
2
2
  /**
3
- * W3C SCXML ↔ XState config, for the pure subset Atlas executes.
3
+ * The XML namespace of Atlas's SCXML extensions (`atlas:name`, `<atlas:meta>`, `atlas:done-event`).
4
+ *
5
+ * The SCXML conventions Atlas reads and writes:
4
6
  *
5
7
  * - `<state>`, `<parallel>`, `<final>`, `initial`, `<transition event target>`.
6
8
  * - `<invoke type="scxml" src="other.scxml" id>` composes another chart; a transition on
@@ -11,9 +13,28 @@ import type { MachineConfig } from './types.js';
11
13
  * that are not strings are written as JSON in an element marked `type="json"`.
12
14
  */
13
15
  export declare const ATLAS_NS = "https://github.com/crvouga/atlas/ns/1";
14
- /** SCXML ids are XML IDs and event attributes are token lists, so names travel in `atlas:name`. */
16
+ /**
17
+ * Turns a business name into a valid SCXML id/event token: ASCII lowercase letters, digits and `-`,
18
+ * starting with a letter or `_` (`s-` is prefixed otherwise). Lossy, so the original name is kept in `atlas:name`.
19
+ *
20
+ * @example scxmlToken('Adds a todo') // 'adds-a-todo'
21
+ */
15
22
  export declare function scxmlToken(name: string): string;
16
- /** Read an SCXML document into an XState machine config. */
23
+ /**
24
+ * Reads an SCXML document into an XState machine config, restoring business names from `atlas:name`.
25
+ *
26
+ * The machine id is the `name` attribute of `<scxml>`, else `fallbackId`. `initial` is the attribute
27
+ * when given, else the first child state. A state's `initial` defaults to its first child state
28
+ * (none for `<parallel>`). Transitions without both an event and a target are skipped.
29
+ *
30
+ * @param xml the document text.
31
+ * @param fallbackId the machine id when the document has no `name`.
32
+ * @throws Error when there is no `<scxml>` root element.
33
+ */
17
34
  export declare function scxmlToMachine(xml: string, fallbackId?: string): MachineConfig;
18
- /** Write an XState machine config as an SCXML document. */
35
+ /**
36
+ * Writes a machine config as an SCXML document with Atlas's `atlas:` extensions, so that
37
+ * `scxmlToMachine(machineToScxml(m))` gives the same chart. Ids are `scxmlToken` forms of the names;
38
+ * the names are kept in `atlas:name`. Only the pure subset is written: `on`, `invoke`, `meta`, nesting.
39
+ */
19
40
  export declare function machineToScxml(machine: MachineConfig): string;
@@ -1,7 +1,20 @@
1
+ /**
2
+ * @module SCXML reader and writer
3
+ *
4
+ * Converts W3C SCXML to and from the XState-shaped `MachineConfig` the rest of Atlas uses, for the
5
+ * pure subset Atlas executes. Business names travel in an `atlas:name` attribute next to a token id,
6
+ * and metadata in the `atlas` namespace, so reading what `machineToScxml` wrote gives the same chart
7
+ * back. Browser-safe (no Node built-ins). Reading is synchronous and keeps its id-to-name table in
8
+ * module state for the duration of one `scxmlToMachine` call, so do not call it re-entrantly.
9
+ *
10
+ * @see docs/statecharts.md
11
+ */
1
12
  import { XMLBuilder, XMLParser } from 'fast-xml-parser';
2
13
  import { invokesOf, targetOf } from './types.js';
3
14
  /**
4
- * W3C SCXML ↔ XState config, for the pure subset Atlas executes.
15
+ * The XML namespace of Atlas's SCXML extensions (`atlas:name`, `<atlas:meta>`, `atlas:done-event`).
16
+ *
17
+ * The SCXML conventions Atlas reads and writes:
5
18
  *
6
19
  * - `<state>`, `<parallel>`, `<final>`, `initial`, `<transition event target>`.
7
20
  * - `<invoke type="scxml" src="other.scxml" id>` composes another chart; a transition on
@@ -65,7 +78,12 @@ function readMeta(node) {
65
78
  }
66
79
  return meta;
67
80
  }
68
- /** SCXML ids are XML IDs and event attributes are token lists, so names travel in `atlas:name`. */
81
+ /**
82
+ * Turns a business name into a valid SCXML id/event token: ASCII lowercase letters, digits and `-`,
83
+ * starting with a letter or `_` (`s-` is prefixed otherwise). Lossy, so the original name is kept in `atlas:name`.
84
+ *
85
+ * @example scxmlToken('Adds a todo') // 'adds-a-todo'
86
+ */
69
87
  export function scxmlToken(name) {
70
88
  const token = name
71
89
  .normalize('NFKD')
@@ -148,7 +166,17 @@ function readState(node, invokeIds) {
148
166
  state.invoke = invokes.length === 1 ? invokes[0] : invokes;
149
167
  return [name, state];
150
168
  }
151
- /** Read an SCXML document into an XState machine config. */
169
+ /**
170
+ * Reads an SCXML document into an XState machine config, restoring business names from `atlas:name`.
171
+ *
172
+ * The machine id is the `name` attribute of `<scxml>`, else `fallbackId`. `initial` is the attribute
173
+ * when given, else the first child state. A state's `initial` defaults to its first child state
174
+ * (none for `<parallel>`). Transitions without both an event and a target are skipped.
175
+ *
176
+ * @param xml the document text.
177
+ * @param fallbackId the machine id when the document has no `name`.
178
+ * @throws Error when there is no `<scxml>` root element.
179
+ */
152
180
  export function scxmlToMachine(xml, fallbackId = 'machine') {
153
181
  const doc = parser.parse(xml);
154
182
  const root = doc.find((n) => local(tagOf(n)) === 'scxml');
@@ -220,7 +248,11 @@ function stateToXml(name, node) {
220
248
  at['atlas:done-event'] = node.meta.doneEvent;
221
249
  return { [tag]: kids, ':@': at };
222
250
  }
223
- /** Write an XState machine config as an SCXML document. */
251
+ /**
252
+ * Writes a machine config as an SCXML document with Atlas's `atlas:` extensions, so that
253
+ * `scxmlToMachine(machineToScxml(m))` gives the same chart. Ids are `scxmlToken` forms of the names;
254
+ * the names are kept in `atlas:name`. Only the pure subset is written: `on`, `invoke`, `meta`, nesting.
255
+ */
224
256
  export function machineToScxml(machine) {
225
257
  const kids = [...metaToXml(machine.meta)];
226
258
  for (const [k, v] of Object.entries(machine.states ?? {}))
@@ -1,5 +1,8 @@
1
1
  /**
2
- * Atlas reads statecharts in two open formats:
2
+ * @module Statechart spec types
3
+ *
4
+ * The data model every other module works on: a chart, a bundle of charts plus journeys, and the
5
+ * helpers that walk and name states and transitions. Atlas reads statecharts in two open formats:
3
6
  *
4
7
  * - W3C SCXML (`*.scxml`), the standard for statecharts.
5
8
  * - XState v5 machine config (`*.machine.json`, `*.machine.yaml`), the JSON form Stately Studio
@@ -9,24 +12,43 @@
9
12
  * walked without running code: states, nesting, parallel regions, final states, event
10
13
  * transitions, statically resolvable child charts (`invoke` with a `src` naming another chart),
11
14
  * and `meta`. Guards, actions, context, delays and `always` are rejected by the linter.
15
+ * This module has no I/O and no Node built-ins.
16
+ *
17
+ * @see docs/statecharts.md
12
18
  */
19
+ /** The object form of a transition. `target` is a state name, optionally prefixed with `#` (a reference by name across the composed product). */
13
20
  export type TransitionConfig = {
14
21
  target: string;
15
22
  };
23
+ /** An `invoke` that runs another chart inside a state. It is never executed: `composeCharts` inlines the child chart statically. */
16
24
  export type InvokeConfig = {
17
25
  /** The id of another chart in the bundle; composed statically. */
18
26
  src: string;
27
+ /** Names the invocation; the parent hears `done.invoke.<id>` (`<src>` when omitted) when the child ends. */
19
28
  id?: string;
20
29
  /** Where the parent goes when the child reaches a final state (`done.invoke.<id>`). */
21
30
  onDone?: string | TransitionConfig;
22
31
  };
32
+ /**
33
+ * The `meta` of a state: the business-language facts about it that Atlas lints, shows and checks.
34
+ * Open object: unknown keys are kept and ignored.
35
+ *
36
+ * @see docs/statecharts.md
37
+ */
23
38
  export type StateMeta = {
39
+ /** What is true in this state. Required on every state by default (`requiredMeta` in the config changes that). */
24
40
  description?: string;
41
+ /** What a person sees in this state, in words. */
25
42
  snapshot?: string;
43
+ /** Business events that happen on entering the state, compared with what event sources observed. */
26
44
  events?: string[];
45
+ /** Whether the behaviour is `confirmed` against the product or only `assumed`. */
27
46
  confidence?: 'confirmed' | 'assumed';
47
+ /** Where the behaviour is documented. */
28
48
  source?: string[];
49
+ /** Things to verify on screen, quoted from the spec; the implementation's `checks()` returns their results. */
29
50
  checks?: string[];
51
+ /** Gherkin-style contracts attached to the state. Core does not read them; they are carried through for viewers. */
30
52
  contracts?: {
31
53
  id: string;
32
54
  name: string;
@@ -39,6 +61,7 @@ export type StateMeta = {
39
61
  docString?: string;
40
62
  }[];
41
63
  }[];
64
+ /** Why a state with no way out is meant to be one. Without it, a state with no outgoing transition is a lint error. */
42
65
  deadEnd?: string;
43
66
  /** Legacy composition: the chart that runs inside this state. Prefer `invoke`. */
44
67
  childMachine?: string;
@@ -48,49 +71,77 @@ export type StateMeta = {
48
71
  doneEvent?: string;
49
72
  [key: string]: unknown;
50
73
  };
74
+ /**
75
+ * One state of an XState-shaped chart, recursively. Keys not listed here (guards, actions, `after`,
76
+ * ...) are accepted by the type so the linter can report them; the planner never executes them.
77
+ */
51
78
  export type StateConfig = {
79
+ /** Set by `composeCharts` to the state's name when absent; used by `#<name>` targets. */
52
80
  id?: string;
81
+ /** The child state entered first. */
53
82
  initial?: string;
83
+ /** `parallel`: all child regions are active together. `final`: the state ends its chart (or hands off to the parent). */
54
84
  type?: 'parallel' | 'final';
55
85
  meta?: StateMeta;
56
86
  states?: Record<string, StateConfig>;
87
+ /** Event name (exact business wording) to its transition: a target string or `{ target }`. */
57
88
  on?: Record<string, TransitionConfig | string>;
89
+ /** Child chart(s) that run inside this state. */
58
90
  invoke?: InvokeConfig | InvokeConfig[];
59
91
  [key: string]: unknown;
60
92
  };
93
+ /** A whole chart: a state config with a required `id`, which is the name other charts `invoke` it by. */
61
94
  export type MachineConfig = StateConfig & {
62
95
  id: string;
63
96
  };
97
+ /** A curated, named sequence of events, replayed by the linter and run as its own path(s). */
64
98
  export type Journey = {
99
+ /** The key in `journeys.yaml`. */
65
100
  name: string;
101
+ /** Empty string when the file gives none. */
66
102
  description: string;
103
+ /** Event names in order, using the exact spec wording. Hand-off events are never listed; the planner inserts them. */
67
104
  events: string[];
105
+ /** State names that must all be active after the last event. Empty when the file gives none. */
68
106
  endsIn: string[];
69
107
  };
108
+ /** One loaded chart file. */
70
109
  export type Chart = {
71
110
  /** Path relative to the spec directory. */
72
111
  file: string;
112
+ /** The notation the file was parsed from. */
73
113
  format: 'scxml' | 'xstate';
74
114
  machine: MachineConfig;
75
115
  };
116
+ /** Everything loaded from a specs directory. */
76
117
  export type SpecBundle = {
118
+ /** The directory the files were read from. */
77
119
  directory: string;
120
+ /** Charts in load order, one per chart id. */
78
121
  charts: Chart[];
122
+ /** Journeys from every journeys file, in file then declaration order. */
79
123
  journeys: Journey[];
80
124
  /** The chart the others are composed into: the one no other chart invokes. */
81
125
  root: string;
82
126
  };
127
+ /** The separator inside a transition id (`<source> :: <event>`). The ids are not escaped, so a state name containing it makes `splitTransitionId` ambiguous. */
83
128
  export declare const TRANSITION_SEPARATOR = " :: ";
129
+ /** The id of a transition: the source state's name and the event, joined by `TRANSITION_SEPARATOR`. */
84
130
  export declare function transitionId(source: string, event: string): string;
131
+ /** Splits a transition id at its first separator into `{ source, event }`; the inverse of `transitionId`. */
85
132
  export declare function splitTransitionId(id: string): {
86
133
  source: string;
87
134
  event: string;
88
135
  };
136
+ /** The state name a transition leads to, with any leading `#` removed; `undefined` when there is no transition. */
89
137
  export declare function targetOf(t: TransitionConfig | string | undefined): string | undefined;
138
+ /** A state found by `walkStates`: its name, its config, and the names of its ancestors from the outermost down. */
90
139
  export type StateEntry = {
91
140
  name: string;
92
141
  node: StateConfig;
93
142
  trail: string[];
94
143
  };
144
+ /** Lists every state under `config` depth-first, parents before their children, in declaration order. The root `config` itself is not listed. */
95
145
  export declare function walkStates(config: StateConfig, trail?: string[]): StateEntry[];
146
+ /** The `invoke` entries of a state as an array (empty when it has none). */
96
147
  export declare function invokesOf(node: StateConfig): InvokeConfig[];
@@ -1,23 +1,47 @@
1
+ /**
2
+ * @module Statechart spec types
3
+ *
4
+ * The data model every other module works on: a chart, a bundle of charts plus journeys, and the
5
+ * helpers that walk and name states and transitions. Atlas reads statecharts in two open formats:
6
+ *
7
+ * - W3C SCXML (`*.scxml`), the standard for statecharts.
8
+ * - XState v5 machine config (`*.machine.json`, `*.machine.yaml`), the JSON form Stately Studio
9
+ * imports and exports.
10
+ *
11
+ * Both load into the XState config shape below. Atlas executes only the pure subset that can be
12
+ * walked without running code: states, nesting, parallel regions, final states, event
13
+ * transitions, statically resolvable child charts (`invoke` with a `src` naming another chart),
14
+ * and `meta`. Guards, actions, context, delays and `always` are rejected by the linter.
15
+ * This module has no I/O and no Node built-ins.
16
+ *
17
+ * @see docs/statecharts.md
18
+ */
19
+ /** The separator inside a transition id (`<source> :: <event>`). The ids are not escaped, so a state name containing it makes `splitTransitionId` ambiguous. */
1
20
  export const TRANSITION_SEPARATOR = ' :: ';
21
+ /** The id of a transition: the source state's name and the event, joined by `TRANSITION_SEPARATOR`. */
2
22
  export function transitionId(source, event) {
3
23
  return `${source}${TRANSITION_SEPARATOR}${event}`;
4
24
  }
25
+ /** Splits a transition id at its first separator into `{ source, event }`; the inverse of `transitionId`. */
5
26
  export function splitTransitionId(id) {
6
27
  const at = id.indexOf(TRANSITION_SEPARATOR);
7
28
  return { source: id.slice(0, at), event: id.slice(at + TRANSITION_SEPARATOR.length) };
8
29
  }
30
+ /** The state name a transition leads to, with any leading `#` removed; `undefined` when there is no transition. */
9
31
  export function targetOf(t) {
10
32
  if (t === undefined)
11
33
  return undefined;
12
34
  const raw = typeof t === 'string' ? t : t.target;
13
35
  return raw.startsWith('#') ? raw.slice(1) : raw;
14
36
  }
37
+ /** Lists every state under `config` depth-first, parents before their children, in declaration order. The root `config` itself is not listed. */
15
38
  export function walkStates(config, trail = []) {
16
39
  return Object.entries(config.states ?? {}).flatMap(([name, node]) => [
17
40
  { name, node, trail },
18
41
  ...walkStates(node, [...trail, name])
19
42
  ]);
20
43
  }
44
+ /** The `invoke` entries of a state as an array (empty when it has none). */
21
45
  export function invokesOf(node) {
22
46
  if (!node.invoke)
23
47
  return [];
@@ -1,24 +1,32 @@
1
1
  import type { Driver, StateImplementation, Timeline } from '../../core/src/index.js';
2
2
  import type { Signal, SignalContext } from '../../core/src/signals.js';
3
+ /** What Detox's `by.*` builders return: an opaque matcher that is only passed back to Detox's `element(...)`. */
4
+ export type DetoxMatcher = unknown;
3
5
  /**
4
6
  * The parts of Detox's global API the driver uses (`device`, `element`, `by`, `waitFor`), typed
5
- * structurally so this package needs no Detox install to build.
7
+ * structurally so this package needs no Detox install to build. Detox's real globals satisfy it.
6
8
  */
7
- export type DetoxMatcher = unknown;
8
9
  export type DetoxApi = {
10
+ /** The device under test; Detox's `device`. */
9
11
  device: {
12
+ /** Launches the app; the driver passes `newInstance: true` and any `launchArgs`. */
10
13
  launchApp(params?: Record<string, unknown>): Promise<void>;
14
+ /** Opens a deep link; when the device lacks it, `goto` throws. */
11
15
  openURL?(params: {
12
16
  url: string;
13
17
  }): Promise<void>;
18
+ /** Terminates the app; skipped when absent. */
14
19
  terminateApp?(): Promise<void>;
20
+ /** Takes a screenshot and resolves to the path of the file Detox wrote. */
15
21
  takeScreenshot(name: string): Promise<string>;
16
22
  };
23
+ /** Detox's `element(matcher)`: the actions the driver performs on an element. */
17
24
  element(matcher: DetoxMatcher): {
18
25
  tap(): Promise<void>;
19
26
  typeText(text: string): Promise<void>;
20
27
  replaceText?(text: string): Promise<void>;
21
28
  };
29
+ /** Detox's `by`: matcher builders. `traits` exists on iOS only. */
22
30
  by: {
23
31
  id(id: string): DetoxMatcher;
24
32
  text(text: string): DetoxMatcher;
@@ -27,37 +35,72 @@ export type DetoxApi = {
27
35
  and?(other: DetoxMatcher): DetoxMatcher;
28
36
  };
29
37
  };
38
+ /** Detox's `waitFor(element)`, used to ask whether an element is visible. */
30
39
  waitFor(element: unknown): {
31
40
  toBeVisible(): {
32
41
  withTimeout(ms: number): Promise<void>;
33
42
  };
34
43
  };
35
44
  };
36
- /** Detox's API plus a `SignalContext`, so implementations written against signals run here too. */
45
+ /**
46
+ * What every event and recogniser receives from `detoxDriver`: Detox's API plus a `SignalContext`,
47
+ * so implementations written against signals run here too. One context is created per path attempt.
48
+ */
37
49
  export type DetoxContext = DetoxApi & SignalContext & {
50
+ /** The step timeline the actions below write to. */
38
51
  timeline: Timeline;
39
- /** Tap an element and log it to the step timeline. */
52
+ /** Tap the element a matcher finds and log it to the step timeline. Rejects with Detox's error if the element is not found. */
40
53
  tap(matcher: DetoxMatcher, label: string): Promise<void>;
54
+ /** Type `text` into the element a matcher finds (Detox `typeText`, which appends) and log it to the step timeline; `label` is the caption. */
41
55
  type(matcher: DetoxMatcher, text: string, label: string): Promise<void>;
42
56
  };
57
+ /** Options of `detoxDriver`. */
43
58
  export type DetoxDriverOptions = {
44
59
  /** Detox's globals; `globalThis` (where Detox puts them) by default. */
45
60
  api?: DetoxApi;
61
+ /** Passed to `device.launchApp` as `launchArgs` at the start of every attempt. */
46
62
  launchArgs?: Record<string, unknown>;
47
63
  };
48
64
  /**
49
- * A signal as a Detox matcher: test IDs are `by.id` (React Native's `testID`), labels `by.label`,
50
- * text `by.text`, a role with a name `by.label` (with the iOS `button` trait when Detox has it).
51
- * Detox matches exact strings, so regular expressions and CSS selectors are refused.
65
+ * Translates a signal into a Detox matcher: test IDs are `by.id` (React Native's `testID`), labels
66
+ * `by.label`, text `by.text`, a role with a name `by.label` (with the iOS `button` trait when Detox
67
+ * has it). Detox matches exact strings, so regular expressions and CSS selectors are refused.
68
+ *
69
+ * @param api the Detox API whose `by` builds the matcher.
70
+ * @throws Error for a `css` signal, a regular expression, or a role without a name.
52
71
  */
53
72
  export declare function detoxMatcher(api: DetoxApi, signal: Signal): DetoxMatcher;
54
73
  /**
55
- * Drive a native app with Detox. Screenshots come from `device.takeScreenshot`. Detox records
56
- * video per test through its artifacts plugin rather than per call, so this driver does not
57
- * record clips; enable Detox's `--record-videos` to keep a video of each attempt.
74
+ * Creates a driver for a native app tested with Detox. Every path attempt relaunches the app
75
+ * (`device.launchApp({ newInstance: true })`) and terminates it afterwards. Screenshots come from
76
+ * `device.takeScreenshot`. Detox records video per test through its artifacts plugin rather than per
77
+ * call, so this driver does not record clips; enable Detox's `--record-videos` to keep a video of
78
+ * each attempt.
79
+ *
80
+ * The Detox globals are read when an attempt opens, so call `runConfig` from inside a Detox test.
81
+ * Signals are resolved with `detoxMatcher`, so regular expressions and CSS selectors are refused.
82
+ *
83
+ * @param options `api` to use instead of the globals, and `launchArgs` for the app.
84
+ * @returns a driver whose context is a `DetoxContext`.
85
+ *
86
+ * @example
87
+ * const config = defineConfig<DetoxContext>({
88
+ * specs: './specs',
89
+ * driver: detoxDriver({ launchArgs: { resetData: true } }),
90
+ * implementation
91
+ * });
92
+ * await runConfig(config, { mode: 'fast' });
58
93
  */
59
94
  export declare function detoxDriver(options?: DetoxDriverOptions): Driver<DetoxContext>;
60
- /** A state recognised by Detox matchers: every `all` visible and no `none` visible. */
95
+ /**
96
+ * Builds a state implementation recognised by Detox matchers: matched when every `all` matcher is
97
+ * visible and no `none` matcher is. `checks` pair a statement from the state's `meta.checks` with
98
+ * the matcher that proves it. Each entry's `name` appears in failure reports. Unlike
99
+ * `screen(...)` from the signals module it takes matchers, not signals, and has no `any`.
100
+ *
101
+ * @example
102
+ * states: { 'No todos': detoxScreen({ all: [{ matcher: by.text('Nothing to do yet'), name: 'empty message' }] }) }
103
+ */
61
104
  export declare function detoxScreen(spec: {
62
105
  all: {
63
106
  matcher: DetoxMatcher;