@crvouga/atlas 0.4.0 → 0.6.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 (444) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/README.md +191 -611
  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 +35 -1
  9. package/dist/core/src/config.d.ts +77 -4
  10. package/dist/core/src/config.js +110 -17
  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 +75 -16
  30. package/dist/core/src/run/execute.js +71 -18
  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 +85 -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 +56 -0
  120. package/dist/reports/src/http-store.js +148 -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 +369 -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/live-reporter.d.ts +34 -0
  147. package/dist/reports/src/live-reporter.js +122 -0
  148. package/dist/reports/src/media-types.d.ts +11 -0
  149. package/dist/reports/src/media-types.js +22 -0
  150. package/dist/reports/src/namespace-guard.d.ts +10 -1
  151. package/dist/reports/src/namespace-guard.js +10 -1
  152. package/dist/reports/src/navigation.d.ts +12 -0
  153. package/dist/reports/src/navigation.js +7 -0
  154. package/dist/reports/src/object-io.d.ts +11 -4
  155. package/dist/reports/src/object-io.js +4 -4
  156. package/dist/reports/src/object-store-conformance.d.ts +27 -0
  157. package/dist/reports/src/object-store-conformance.js +87 -0
  158. package/dist/reports/src/object-store.d.ts +33 -24
  159. package/dist/reports/src/object-store.js +17 -24
  160. package/dist/reports/src/parse-with.d.ts +16 -0
  161. package/dist/reports/src/parse-with.js +14 -0
  162. package/dist/reports/src/performance-part.d.ts +25 -1
  163. package/dist/reports/src/performance-part.js +15 -1
  164. package/dist/reports/src/performance.d.ts +22 -2
  165. package/dist/reports/src/performance.js +12 -2
  166. package/dist/reports/src/persist.d.ts +12 -3
  167. package/dist/reports/src/persist.js +12 -3
  168. package/dist/reports/src/phone.d.ts +18 -1
  169. package/dist/reports/src/phone.js +18 -1
  170. package/dist/reports/src/protocol.d.ts +26 -4
  171. package/dist/reports/src/protocol.js +15 -4
  172. package/dist/reports/src/publication.d.ts +21 -1
  173. package/dist/reports/src/publication.js +21 -1
  174. package/dist/reports/src/publish-checks.d.ts +35 -0
  175. package/dist/reports/src/publish-checks.js +122 -0
  176. package/dist/reports/src/publish.d.ts +42 -9
  177. package/dist/reports/src/publish.js +36 -7
  178. package/dist/reports/src/read.d.ts +46 -16
  179. package/dist/reports/src/read.js +38 -14
  180. package/dist/reports/src/recording-bundle.d.ts +13 -2
  181. package/dist/reports/src/recording-bundle.js +4 -2
  182. package/dist/reports/src/recording-keys.d.ts +15 -1
  183. package/dist/reports/src/recording-keys.js +15 -1
  184. package/dist/reports/src/remote-report.d.ts +28 -7
  185. package/dist/reports/src/remote-report.js +15 -7
  186. package/dist/reports/src/report-cli.d.ts +51 -0
  187. package/dist/reports/src/report-cli.js +486 -0
  188. package/dist/reports/src/report-index.d.ts +99 -0
  189. package/dist/reports/src/report-index.js +337 -0
  190. package/dist/reports/src/report-loader.d.ts +10 -0
  191. package/dist/reports/src/report-loader.js +6 -0
  192. package/dist/reports/src/report-parts.d.ts +29 -3
  193. package/dist/reports/src/report-parts.js +37 -3
  194. package/dist/reports/src/report-status.d.ts +48 -0
  195. package/dist/reports/src/report-status.js +156 -0
  196. package/dist/reports/src/report-types.d.ts +73 -0
  197. package/dist/reports/src/report-types.js +3 -0
  198. package/dist/reports/src/reporter.d.ts +67 -0
  199. package/dist/reports/src/reporter.js +128 -0
  200. package/dist/reports/src/reports-explorer-route.d.ts +541 -0
  201. package/dist/reports/src/reports-explorer-route.js +11 -0
  202. package/dist/reports/src/reports-list-route.d.ts +9 -0
  203. package/dist/reports/src/reports-list-route.js +9 -0
  204. package/dist/reports/src/reports-route.d.ts +561 -22
  205. package/dist/reports/src/reports-route.js +11 -3
  206. package/dist/reports/src/reports-store.d.ts +19 -2
  207. package/dist/reports/src/reports-store.js +10 -2
  208. package/dist/reports/src/resilient-cache.d.ts +14 -1
  209. package/dist/reports/src/resilient-cache.js +8 -1
  210. package/dist/reports/src/retention.d.ts +17 -1
  211. package/dist/reports/src/retention.js +5 -1
  212. package/dist/reports/src/run-bundle.d.ts +63 -0
  213. package/dist/reports/src/run-bundle.js +159 -0
  214. package/dist/reports/src/s3-store.d.ts +79 -0
  215. package/dist/reports/src/s3-store.js +295 -0
  216. package/dist/reports/src/scenario.d.ts +14 -4
  217. package/dist/reports/src/scenario.js +5 -4
  218. package/dist/reports/src/sigv4.d.ts +72 -0
  219. package/dist/reports/src/sigv4.js +96 -0
  220. package/dist/reports/src/snapshot-bundle.d.ts +24 -1
  221. package/dist/reports/src/snapshot-bundle.js +27 -2
  222. package/dist/reports/src/snapshot-surface.d.ts +20 -9
  223. package/dist/reports/src/snapshot-surface.js +32 -19
  224. package/dist/reports/src/source-content.d.ts +23 -0
  225. package/dist/reports/src/source-content.js +30 -1
  226. package/dist/reports/src/source-entries.d.ts +13 -0
  227. package/dist/reports/src/source-entries.js +6 -0
  228. package/dist/reports/src/source-part.d.ts +15 -0
  229. package/dist/reports/src/source-part.js +8 -0
  230. package/dist/reports/src/source-reader.d.ts +11 -0
  231. package/dist/reports/src/source-reader.js +5 -0
  232. package/dist/reports/src/spec-evidence.d.ts +12 -2
  233. package/dist/reports/src/spec-evidence.js +6 -2
  234. package/dist/reports/src/spec-inventory.d.ts +15 -1
  235. package/dist/reports/src/spec-inventory.js +22 -1
  236. package/dist/reports/src/spec-link.d.ts +28 -0
  237. package/dist/reports/src/spec-link.js +70 -0
  238. package/dist/reports/src/spec-set.d.ts +63 -0
  239. package/dist/reports/src/spec-set.js +177 -0
  240. package/dist/reports/src/status.d.ts +10 -0
  241. package/dist/reports/src/status.js +5 -0
  242. package/dist/reports/src/store-prefix.d.ts +28 -0
  243. package/dist/reports/src/store-prefix.js +22 -0
  244. package/dist/reports/src/store-url.d.ts +89 -0
  245. package/dist/reports/src/store-url.js +160 -0
  246. package/dist/reports/src/test-catalog-entity.d.ts +11 -0
  247. package/dist/reports/src/test-catalog-entity.js +6 -0
  248. package/dist/reports/src/types.d.ts +6 -1
  249. package/dist/reports/src/use-report-nav.d.ts +35 -0
  250. package/dist/reports/src/use-report-nav.js +12 -0
  251. package/dist/runners/src/codecept.d.ts +14 -0
  252. package/dist/runners/src/codecept.js +16 -0
  253. package/dist/runners/src/jest.d.ts +50 -0
  254. package/dist/runners/src/jest.js +52 -0
  255. package/dist/runners/src/mocha.d.ts +40 -0
  256. package/dist/runners/src/mocha.js +39 -0
  257. package/dist/runners/src/node-test.d.ts +28 -0
  258. package/dist/runners/src/node-test.js +44 -0
  259. package/dist/runners/src/publish.d.ts +30 -0
  260. package/dist/runners/src/publish.js +68 -0
  261. package/dist/schema/src/api.d.ts +800 -0
  262. package/dist/schema/src/api.js +201 -0
  263. package/dist/schema/src/cli-results.d.ts +210 -0
  264. package/dist/schema/src/cli-results.js +124 -0
  265. package/dist/schema/src/common.d.ts +53 -0
  266. package/dist/schema/src/common.js +42 -0
  267. package/dist/schema/src/index.d.ts +16 -0
  268. package/dist/schema/src/index.js +16 -0
  269. package/dist/schema/src/layer.d.ts +2273 -0
  270. package/dist/schema/src/layer.js +462 -0
  271. package/dist/schema/src/live-run.d.ts +123 -0
  272. package/dist/schema/src/live-run.js +30 -0
  273. package/dist/schema/src/manifest.d.ts +97 -2
  274. package/dist/schema/src/manifest.js +84 -0
  275. package/dist/schema/src/project.d.ts +20 -0
  276. package/dist/schema/src/project.js +10 -0
  277. package/dist/schema/src/report-sources.d.ts +29 -0
  278. package/dist/schema/src/report-sources.js +27 -1
  279. package/dist/schema/src/runs-index.d.ts +17 -1
  280. package/dist/schema/src/runs-index.js +15 -0
  281. package/dist/schema/src/server-config.d.ts +177 -0
  282. package/dist/schema/src/server-config.js +85 -0
  283. package/dist/schema/src/spec.d.ts +69 -0
  284. package/dist/schema/src/spec.js +58 -0
  285. package/dist/server/src/app.d.ts +72 -0
  286. package/dist/server/src/app.js +557 -0
  287. package/dist/server/src/auth.d.ts +41 -0
  288. package/dist/server/src/auth.js +59 -0
  289. package/dist/server/src/config.d.ts +83 -0
  290. package/dist/server/src/config.js +204 -0
  291. package/dist/server/src/dev.d.ts +12 -0
  292. package/dist/server/src/dev.js +89 -0
  293. package/dist/server/src/events.d.ts +29 -0
  294. package/dist/server/src/events.js +101 -0
  295. package/dist/server/src/host.d.ts +30 -0
  296. package/dist/server/src/host.js +115 -0
  297. package/dist/server/src/index.d.ts +18 -0
  298. package/dist/server/src/index.js +18 -0
  299. package/dist/server/src/live-runs.d.ts +52 -0
  300. package/dist/server/src/live-runs.js +229 -0
  301. package/dist/server/src/llms.d.ts +19 -0
  302. package/dist/server/src/llms.js +63 -0
  303. package/dist/server/src/main.d.ts +30 -0
  304. package/dist/server/src/main.js +114 -0
  305. package/dist/server/src/openapi.d.ts +56 -0
  306. package/dist/server/src/openapi.js +438 -0
  307. package/dist/server/src/problem.d.ts +8 -0
  308. package/dist/server/src/problem.js +39 -0
  309. package/dist/server/src/projects.d.ts +3 -0
  310. package/dist/server/src/projects.js +154 -0
  311. package/dist/server/src/settings-page.d.ts +9 -0
  312. package/dist/server/src/settings-page.js +93 -0
  313. package/dist/server/src/settings.d.ts +23 -0
  314. package/dist/server/src/settings.js +72 -0
  315. package/dist/server/src/site.d.ts +15 -0
  316. package/dist/server/src/site.js +78 -0
  317. package/dist/server/src/store-api.d.ts +28 -0
  318. package/dist/server/src/store-api.js +180 -0
  319. package/dist/server/src/validate.d.ts +71 -0
  320. package/dist/server/src/validate.js +197 -0
  321. package/dist/vitest/src/index.d.ts +27 -5
  322. package/dist/vitest/src/index.js +18 -5
  323. package/dist/webdriver/src/driver.d.ts +63 -11
  324. package/dist/webdriver/src/driver.js +57 -6
  325. package/dist/webdriver/src/index.d.ts +8 -0
  326. package/dist/webdriver/src/index.js +1 -0
  327. package/dist/webdriver/src/protocol.d.ts +75 -6
  328. package/dist/webdriver/src/protocol.js +79 -6
  329. package/docs/agents.md +137 -0
  330. package/docs/deploying.md +345 -0
  331. package/docs/dogfooding.md +175 -0
  332. package/docs/extending.md +242 -0
  333. package/docs/integrating.md +485 -0
  334. package/docs/reference/bun.md +141 -0
  335. package/docs/reference/cli.md +148 -0
  336. package/docs/reference/core.md +2432 -0
  337. package/docs/reference/detox.md +150 -0
  338. package/docs/reference/http-api.md +799 -0
  339. package/docs/reference/playwright.md +303 -0
  340. package/docs/reference/reports.md +7152 -0
  341. package/docs/reference/runners.md +169 -0
  342. package/docs/reference/schema.md +1762 -0
  343. package/docs/reference/server.md +825 -0
  344. package/docs/reference/vitest.md +45 -0
  345. package/docs/reference/webdriver.md +330 -0
  346. package/docs/report-backends.md +144 -0
  347. package/docs/report-contract.md +400 -0
  348. package/docs/reporting-issues.md +160 -0
  349. package/docs/runners.md +69 -0
  350. package/docs/server.md +321 -0
  351. package/docs/statecharts.md +643 -0
  352. package/llms-full.txt +4114 -0
  353. package/llms.txt +49 -0
  354. package/package.json +61 -11
  355. package/packages/core/README.md +2 -1
  356. package/packages/reports/README.md +65 -0
  357. package/packages/reports/STORAGE.md +4 -0
  358. package/packages/runners/README.md +6 -0
  359. package/packages/runners/compat/codecept.cjs +2 -0
  360. package/packages/runners/compat/jest.cjs +2 -0
  361. package/packages/runners/compat/mocha.cjs +2 -0
  362. package/packages/schema/README.md +14 -0
  363. package/packages/schema/schemas/atlas-change.schema.json +4 -0
  364. package/packages/schema/schemas/check-detail.schema.json +1032 -0
  365. package/packages/schema/schemas/checks-result.schema.json +26 -0
  366. package/packages/schema/schemas/command-error.schema.json +35 -0
  367. package/packages/schema/schemas/doctor-result.schema.json +60 -0
  368. package/packages/schema/schemas/effective-delta.schema.json +490 -0
  369. package/packages/schema/schemas/effective-evidence.schema.json +471 -0
  370. package/packages/schema/schemas/evidence-page.schema.json +271 -0
  371. package/packages/schema/schemas/hello-event.schema.json +26 -0
  372. package/packages/schema/schemas/init-plan.schema.json +347 -0
  373. package/packages/schema/schemas/layer-rows.schema.json +199 -0
  374. package/packages/schema/schemas/layer.schema.json +2888 -0
  375. package/packages/schema/schemas/live-run-start.schema.json +42 -0
  376. package/packages/schema/schemas/live-run-update.schema.json +93 -0
  377. package/packages/schema/schemas/live-run.schema.json +225 -0
  378. package/packages/schema/schemas/merge-result.schema.json +40 -0
  379. package/packages/schema/schemas/outline.schema.json +62 -0
  380. package/packages/schema/schemas/problem.schema.json +37 -0
  381. package/packages/schema/schemas/project-slug.schema.json +8 -0
  382. package/packages/schema/schemas/project.schema.json +22 -0
  383. package/packages/schema/schemas/projects.schema.json +33 -0
  384. package/packages/schema/schemas/publish-checks.schema.json +1413 -0
  385. package/packages/schema/schemas/publish-result.schema.json +168 -0
  386. package/packages/schema/schemas/ready.schema.json +68 -0
  387. package/packages/schema/schemas/report-event.schema.json +100 -0
  388. package/packages/schema/schemas/report-status.schema.json +370 -0
  389. package/packages/schema/schemas/server-config.schema.json +208 -0
  390. package/packages/schema/schemas/server-editable-settings.schema.json +132 -0
  391. package/packages/schema/schemas/server-info.schema.json +114 -0
  392. package/packages/schema/schemas/server-settings-snapshot.schema.json +285 -0
  393. package/packages/schema/schemas/spec-set.schema.json +103 -0
  394. package/packages/schema/schemas/store-listing.schema.json +29 -0
  395. package/packages/schema/schemas/store-write-result.schema.json +28 -0
  396. package/packages/schema/schemas/stream-result.schema.json +59 -0
  397. package/packages/server/README.md +43 -0
  398. package/packages/server/openapi.json +11021 -0
  399. package/packages/visualizer/README.md +32 -11
  400. package/packages/visualizer/bin/atlas-client.mjs +176 -0
  401. package/packages/visualizer/bin/atlas-visualizer.mjs +2 -175
  402. package/packages/visualizer/src/app/AppShell.tsx +32 -16
  403. package/packages/visualizer/src/app/report-sources.tsx +7 -4
  404. package/packages/visualizer/src/app/router.tsx +3 -3
  405. package/packages/visualizer/src/components/ActivityIndicator.module.css +4 -0
  406. package/packages/visualizer/src/components/ActivityIndicator.tsx +6 -0
  407. package/packages/visualizer/src/components/Header.module.css +101 -192
  408. package/packages/visualizer/src/components/Header.tsx +88 -13
  409. package/packages/visualizer/src/components/ProjectPicker.tsx +64 -0
  410. package/packages/visualizer/src/data/adapters/adapter.ts +5 -17
  411. package/packages/visualizer/src/data/adapters/index.ts +10 -1
  412. package/packages/visualizer/src/data/adapters/report-backend.test.ts +3 -2
  413. package/packages/visualizer/src/data/adapters/report-backend.ts +1 -1
  414. package/packages/visualizer/src/data/queries.ts +14 -7
  415. package/packages/visualizer/src/evidence/api.ts +16 -3
  416. package/packages/visualizer/src/evidence/artifacts.module.css +213 -0
  417. package/packages/visualizer/src/evidence/artifacts.tsx +272 -0
  418. package/packages/visualizer/src/evidence/check-detail.tsx +21 -4
  419. package/packages/visualizer/src/evidence/document-page.tsx +6 -2
  420. package/packages/visualizer/src/evidence/evidence-context.tsx +79 -12
  421. package/packages/visualizer/src/evidence/evidence.module.css +11 -1
  422. package/packages/visualizer/src/evidence/feature-page.tsx +7 -3
  423. package/packages/visualizer/src/evidence/model-page.tsx +6 -2
  424. package/packages/visualizer/src/evidence/project-home.tsx +45 -0
  425. package/packages/visualizer/src/evidence/recording-page.tsx +4 -1
  426. package/packages/visualizer/src/evidence/spec-index.tsx +2 -1
  427. package/packages/visualizer/src/evidence/spec-page.tsx +23 -16
  428. package/packages/visualizer/src/evidence/test-filter.tsx +21 -0
  429. package/packages/visualizer/src/find/Finder.tsx +1 -7
  430. package/packages/visualizer/src/find/open.ts +4 -0
  431. package/packages/visualizer/src/live/live-query.ts +21 -0
  432. package/packages/visualizer/src/live/live-runs.tsx +69 -0
  433. package/packages/visualizer/src/live/live-stream.ts +225 -0
  434. package/packages/visualizer/src/live/report-progress.ts +62 -0
  435. package/packages/visualizer/src/live/test-progress.tsx +34 -0
  436. package/packages/visualizer/src/runtime.ts +35 -0
  437. package/packages/visualizer/src/state/ui-store.ts +3 -2
  438. package/packages/visualizer/src/views/ChartPage.tsx +2 -0
  439. package/packages/visualizer/src/views/ChartTests.tsx +43 -0
  440. package/packages/visualizer/src/views/SidePanel.tsx +2 -0
  441. package/packages/visualizer/vite/atlas-files.test.ts +4 -4
  442. package/packages/visualizer/vite/atlas-files.ts +1 -5
  443. package/packages/visualizer/vite/atlas-server-proxy.ts +37 -0
  444. package/packages/visualizer/vite.config.ts +11 -3
@@ -1,3 +1,14 @@
1
+ /**
2
+ * @module UI signals
3
+ *
4
+ * A driver-neutral vocabulary for saying what is on screen (`testId`, `role`, `label`, `text`, `css`),
5
+ * and `screen(...)`, which builds a state recogniser from signals. Every UI driver (Playwright, Bun
6
+ * WebView, WebDriver, Detox) resolves the same signals against its own UI tree, so an implementation
7
+ * written with them runs on any of them. Also holds the wire form and the in-page probe used by drivers
8
+ * that evaluate JavaScript in a page. This module is browser-safe and has no driver dependencies.
9
+ *
10
+ * @see docs/statecharts.md
11
+ */
1
12
  import type { StateImplementation } from './run/types.js';
2
13
  /**
3
14
  * A UI signal: something visible (or not) that proves where the app is. Test IDs first, then
@@ -19,35 +30,56 @@ export type Signal = {
19
30
  } | {
20
31
  css: string;
21
32
  };
33
+ /** A signal for the element with this test ID (`data-testid` on the web, the accessibility identifier on native). */
22
34
  export declare const testId: (id: string) => Signal;
35
+ /** A signal for visible text: a string matches as a case-insensitive substring unless `exact`, a RegExp is tested as is. */
23
36
  export declare const text: (value: string | RegExp, options?: {
24
37
  exact?: boolean;
25
38
  }) => Signal;
39
+ /** A signal for an element with an accessibility role (`button`, `heading`, ...), optionally filtered by its accessible name (same matching as `text`). */
26
40
  export declare const role: (r: string, name?: string | RegExp, options?: {
27
41
  exact?: boolean;
28
42
  }) => Signal;
43
+ /** A signal for a form control by its label text. */
29
44
  export declare const label: (value: string | RegExp) => Signal;
45
+ /** A signal for a CSS selector. Web only: the WebDriver and Detox drivers throw for it in native sessions, so prefer the other signals. */
30
46
  export declare const css: (selector: string) => Signal;
47
+ /** Describes a signal in words for recogniser output and failure messages, e.g. `button "Add"`. */
31
48
  export declare function describeSignal(signal: Signal): string;
49
+ /** What a screen looks like, as signals. */
32
50
  export type SignatureSpec<S = Signal> = {
51
+ /** Every one must be visible. */
33
52
  all?: S[];
53
+ /** At least one must be visible (ignored when empty). */
34
54
  any?: S[];
55
+ /** None may be visible. */
35
56
  none?: S[];
36
57
  };
58
+ /** A `SignatureSpec` plus the optional parts of a `StateImplementation`, which are passed through. */
37
59
  export type ScreenSpec<C, S = Signal> = SignatureSpec<S> & {
60
+ /** Each `check` is a statement from the state's `meta.checks`; it passes when its `signal` is visible. */
38
61
  checks?: {
39
62
  check: string;
40
63
  signal: S;
41
64
  }[];
65
+ /** See `StateImplementation.transient`. */
42
66
  transient?: boolean;
67
+ /** See `StateImplementation.sameAs`. */
43
68
  sameAs?: string;
69
+ /** See `StateImplementation.lookIn`. */
44
70
  lookIn?: (ctx: C) => Promise<void>;
71
+ /** See `StateImplementation.settle`. */
45
72
  settle?: (ctx: C) => Promise<void>;
46
73
  };
47
74
  /**
48
- * Build `screen()` for a driver from one question: is this signal visible right now? A state is
49
- * recognised when every `all` is visible, one `any` is visible and no `none` is. Drivers with
50
- * their own locators (WebDriver's) pass their signal type and how to describe it.
75
+ * Builds a `screen()` function for a driver from one question: is this signal visible right now?
76
+ * A state is recognised when every `all` is visible, one `any` is visible and no `none` is; the result
77
+ * lists every signal looked at with whether it was visible, for failure reports. An `isVisible` that
78
+ * rejects counts as not visible. Drivers with their own locators (WebDriver's) pass their signal type
79
+ * and how to describe it.
80
+ *
81
+ * @param isVisible answers whether one signal is visible in the context.
82
+ * @param describe names a signal in words.
51
83
  */
52
84
  export declare function signatureScreen<C, S = Signal>(isVisible: (ctx: C, signal: S) => Promise<boolean>, describe: (signal: S) => string): (spec: ScreenSpec<C, S>) => StateImplementation<C>;
53
85
  /**
@@ -58,14 +90,25 @@ export declare function signatureScreen<C, S = Signal>(isVisible: (ctx: C, signa
58
90
  export type SignalContext = {
59
91
  /** Open a URL (a path resolves against the driver's base URL; a deep link in a native app). */
60
92
  goto(url: string): Promise<void>;
93
+ /** Whether the signal is visible now. */
61
94
  isVisible(signal: Signal): Promise<boolean>;
95
+ /** Actions a person does. Drivers log each to the step's timeline, which becomes the clip's captions. */
62
96
  user: {
97
+ /** Taps or clicks the target; `label` is the caption shown for it. */
63
98
  tap(target: Signal, label: string): Promise<void>;
99
+ /** Types `text` into the target; `label` is the caption shown for it. */
64
100
  type(target: Signal, text: string, label: string): Promise<void>;
65
101
  };
66
102
  };
67
- /** A state recognised from signals on any driver that provides a `SignalContext`. */
103
+ /**
104
+ * Builds a state implementation that is recognised from signals on any driver that provides a
105
+ * `SignalContext`.
106
+ *
107
+ * @example
108
+ * states: { 'No todos': screen({ all: [text('Nothing to do yet')], none: [role('listitem')] }) }
109
+ */
68
110
  export declare const screen: (spec: ScreenSpec<SignalContext, Signal>) => StateImplementation<SignalContext>;
111
+ /** A string or regular expression as JSON. */
69
112
  type WireMatch = {
70
113
  text: string;
71
114
  exact: boolean;
@@ -73,6 +116,7 @@ type WireMatch = {
73
116
  regex: string;
74
117
  flags: string;
75
118
  };
119
+ /** A `Signal` as plain JSON, the form sent to the in-page `DOM_PROBE`. */
76
120
  export type WireSignal = {
77
121
  kind: 'css';
78
122
  selector: string;
@@ -90,7 +134,7 @@ export type WireSignal = {
90
134
  kind: 'text';
91
135
  match: WireMatch;
92
136
  };
93
- /** A signal as JSON, for a probe that runs inside the page. */
137
+ /** Converts a signal to its JSON form for a probe that runs inside the page. */
94
138
  export declare function toWire(signal: Signal): WireSignal;
95
139
  /** Where a probe found a signal: whether it is visible, and the centre of the first visible match in CSS pixels. */
96
140
  export type DomProbeResult = {
@@ -1,8 +1,14 @@
1
+ /** A signal for the element with this test ID (`data-testid` on the web, the accessibility identifier on native). */
1
2
  export const testId = (id) => ({ testId: id });
3
+ /** A signal for visible text: a string matches as a case-insensitive substring unless `exact`, a RegExp is tested as is. */
2
4
  export const text = (value, options = {}) => ({ text: value, ...options });
5
+ /** A signal for an element with an accessibility role (`button`, `heading`, ...), optionally filtered by its accessible name (same matching as `text`). */
3
6
  export const role = (r, name, options = {}) => ({ role: r, ...(name ? { name } : {}), ...options });
7
+ /** A signal for a form control by its label text. */
4
8
  export const label = (value) => ({ label: value });
9
+ /** A signal for a CSS selector. Web only: the WebDriver and Detox drivers throw for it in native sessions, so prefer the other signals. */
5
10
  export const css = (selector) => ({ css: selector });
11
+ /** Describes a signal in words for recogniser output and failure messages, e.g. `button "Add"`. */
6
12
  export function describeSignal(signal) {
7
13
  if ('testId' in signal)
8
14
  return `test ID "${signal.testId}"`;
@@ -15,9 +21,14 @@ export function describeSignal(signal) {
15
21
  return `text ${String(signal.text)}`;
16
22
  }
17
23
  /**
18
- * Build `screen()` for a driver from one question: is this signal visible right now? A state is
19
- * recognised when every `all` is visible, one `any` is visible and no `none` is. Drivers with
20
- * their own locators (WebDriver's) pass their signal type and how to describe it.
24
+ * Builds a `screen()` function for a driver from one question: is this signal visible right now?
25
+ * A state is recognised when every `all` is visible, one `any` is visible and no `none` is; the result
26
+ * lists every signal looked at with whether it was visible, for failure reports. An `isVisible` that
27
+ * rejects counts as not visible. Drivers with their own locators (WebDriver's) pass their signal type
28
+ * and how to describe it.
29
+ *
30
+ * @param isVisible answers whether one signal is visible in the context.
31
+ * @param describe names a signal in words.
21
32
  */
22
33
  export function signatureScreen(isVisible, describe) {
23
34
  const visible = (ctx, signal) => isVisible(ctx, signal).catch(() => false);
@@ -58,10 +69,16 @@ export function signatureScreen(isVisible, describe) {
58
69
  };
59
70
  };
60
71
  }
61
- /** A state recognised from signals on any driver that provides a `SignalContext`. */
72
+ /**
73
+ * Builds a state implementation that is recognised from signals on any driver that provides a
74
+ * `SignalContext`.
75
+ *
76
+ * @example
77
+ * states: { 'No todos': screen({ all: [text('Nothing to do yet')], none: [role('listitem')] }) }
78
+ */
62
79
  export const screen = signatureScreen((ctx, signal) => ctx.isVisible(signal), describeSignal);
63
80
  const wire = (value, exact = false) => typeof value === 'string' ? { text: value, exact } : { regex: value.source, flags: value.flags };
64
- /** A signal as JSON, for a probe that runs inside the page. */
81
+ /** Converts a signal to its JSON form for a probe that runs inside the page. */
65
82
  export function toWire(signal) {
66
83
  if ('testId' in signal)
67
84
  return { kind: 'testId', id: signal.testId };
@@ -1,11 +1,24 @@
1
+ /**
2
+ * @module Static chart composition
3
+ *
4
+ * Flattens a bundle of charts into one machine by inlining each child chart into the state that
5
+ * invokes it, so a plain graph traversal sees the whole product. Pure and deterministic; the input
6
+ * bundle is not modified. State names are global across the composed product (nothing is renamed or
7
+ * namespaced), which is why they must be unique across charts.
8
+ *
9
+ * @see docs/statecharts.md
10
+ */
1
11
  import type { MachineConfig, SpecBundle } from './types.js';
12
+ /** A child chart's final state and the event it passes to the parent, which the planner and replay insert automatically. */
2
13
  export type HandOff = {
3
14
  finalState: string;
4
15
  event: string;
5
16
  parentState: string;
6
17
  childChart: string;
7
18
  };
19
+ /** The result of composing a bundle. */
8
20
  export type Composition = {
21
+ /** The single flattened machine (a deep copy; the bundle is untouched). */
9
22
  machine: MachineConfig;
10
23
  /** Which chart each state came from. */
11
24
  chartOf: Map<string, string>;
@@ -15,7 +28,7 @@ export type Composition = {
15
28
  hosts: Map<string, string>;
16
29
  };
17
30
  /**
18
- * Inline every child chart where its parent invokes it, so XState's graph traversal (which cannot
31
+ * Inlines every child chart where its parent invokes it, so XState's graph traversal (which cannot
19
32
  * enter an invoked actor) walks straight through. Supports:
20
33
  *
21
34
  * - XState `invoke: { src, id, onDone }` and SCXML `<invoke>` + `done.invoke.<id>`;
@@ -24,5 +37,14 @@ export type Composition = {
24
37
  *
25
38
  * A child's final states stay as states (they keep their screenshots and checks) but stop being
26
39
  * final: each takes the parent's transition for its hand-off event.
40
+ *
41
+ * Every state without an `id` gets its own name as `id`. A child's `initial` replaces the host
42
+ * state's `initial`, and the host's transitions that consumed a hand-off event are removed from it.
43
+ *
44
+ * @throws Error when the root chart is not loaded, an invoked chart is not loaded, charts invoke
45
+ * each other in a cycle, or a child's final state has no matching transition (or `onDone`) in the parent.
46
+ *
47
+ * @example
48
+ * const { machine, handOffs } = composeCharts(loadSpecDirectory('./specs'));
27
49
  */
28
50
  export declare function composeCharts(bundle: SpecBundle): Composition;
@@ -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 ?? {}))