@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.
- package/CHANGELOG.md +13 -1
- package/README.md +191 -611
- package/dist/bun/src/driver.d.ts +41 -7
- package/dist/bun/src/driver.js +47 -6
- package/dist/bun/src/index.d.ts +8 -0
- package/dist/bun/src/index.js +8 -0
- package/dist/core/src/cli.d.ts +14 -1
- package/dist/core/src/cli.js +35 -1
- package/dist/core/src/config.d.ts +77 -4
- package/dist/core/src/config.js +110 -17
- package/dist/core/src/events/cloudevents.d.ts +54 -9
- package/dist/core/src/events/cloudevents.js +60 -9
- package/dist/core/src/graph.d.ts +21 -0
- package/dist/core/src/graph.js +26 -0
- package/dist/core/src/index.d.ts +11 -0
- package/dist/core/src/index.js +11 -0
- package/dist/core/src/lint.d.ts +30 -0
- package/dist/core/src/lint.js +13 -0
- package/dist/core/src/plan.d.ts +39 -1
- package/dist/core/src/plan.js +28 -1
- package/dist/core/src/privacy.d.ts +29 -2
- package/dist/core/src/privacy.js +19 -2
- package/dist/core/src/report/formats.d.ts +34 -4
- package/dist/core/src/report/formats.js +24 -4
- package/dist/core/src/report/markdown.d.ts +15 -0
- package/dist/core/src/report/markdown.js +8 -0
- package/dist/core/src/run/clients.d.ts +44 -5
- package/dist/core/src/run/clients.js +46 -2
- package/dist/core/src/run/execute.d.ts +75 -16
- package/dist/core/src/run/execute.js +71 -18
- package/dist/core/src/run/frames.d.ts +13 -4
- package/dist/core/src/run/frames.js +19 -4
- package/dist/core/src/run/http.d.ts +34 -1
- package/dist/core/src/run/http.js +14 -1
- package/dist/core/src/run/types.d.ts +76 -3
- package/dist/core/src/run/types.js +19 -3
- package/dist/core/src/signals.d.ts +49 -5
- package/dist/core/src/signals.js +22 -5
- package/dist/core/src/spec/compose.d.ts +23 -1
- package/dist/core/src/spec/compose.js +10 -1
- package/dist/core/src/spec/index.d.ts +9 -1
- package/dist/core/src/spec/index.js +9 -1
- package/dist/core/src/spec/load.d.ts +22 -1
- package/dist/core/src/spec/load.js +31 -1
- package/dist/core/src/spec/parse.d.ts +16 -2
- package/dist/core/src/spec/parse.js +25 -2
- package/dist/core/src/spec/scxml.d.ts +25 -4
- package/dist/core/src/spec/scxml.js +36 -4
- package/dist/core/src/spec/types.d.ts +52 -1
- package/dist/core/src/spec/types.js +24 -0
- package/dist/detox/src/index.d.ts +54 -11
- package/dist/detox/src/index.js +45 -7
- package/dist/playwright/src/driver.d.ts +39 -3
- package/dist/playwright/src/driver.js +27 -3
- package/dist/playwright/src/index.d.ts +10 -0
- package/dist/playwright/src/index.js +10 -0
- package/dist/playwright/src/media.d.ts +50 -4
- package/dist/playwright/src/media.js +55 -4
- package/dist/playwright/src/signals.d.ts +44 -5
- package/dist/playwright/src/signals.js +29 -5
- package/dist/reports/src/attachment-files.d.ts +44 -0
- package/dist/reports/src/attachment-files.js +121 -0
- package/dist/reports/src/attachment-response.d.ts +31 -0
- package/dist/reports/src/attachment-response.js +55 -0
- package/dist/reports/src/aws-credentials.d.ts +48 -0
- package/dist/reports/src/aws-credentials.js +221 -0
- package/dist/reports/src/browser-navigation.d.ts +14 -0
- package/dist/reports/src/browser-navigation.js +7 -0
- package/dist/reports/src/bundle.d.ts +34 -2
- package/dist/reports/src/bundle.js +38 -2
- package/dist/reports/src/catalog.d.ts +34 -3
- package/dist/reports/src/catalog.js +17 -3
- package/dist/reports/src/cli-stores.d.ts +36 -0
- package/dist/reports/src/cli-stores.js +73 -0
- package/dist/reports/src/clock.d.ts +7 -2
- package/dist/reports/src/clock.js +5 -2
- package/dist/reports/src/completion-order.d.ts +18 -5
- package/dist/reports/src/completion-order.js +18 -5
- package/dist/reports/src/compose.d.ts +80 -0
- package/dist/reports/src/compose.js +117 -0
- package/dist/reports/src/copy-store.d.ts +29 -0
- package/dist/reports/src/copy-store.js +52 -0
- package/dist/reports/src/directory-outline.d.ts +38 -0
- package/dist/reports/src/directory-outline.js +103 -0
- package/dist/reports/src/directory-store.d.ts +20 -0
- package/dist/reports/src/directory-store.js +166 -0
- package/dist/reports/src/doctor.d.ts +29 -0
- package/dist/reports/src/doctor.js +85 -0
- package/dist/reports/src/effective-delta.d.ts +34 -0
- package/dist/reports/src/effective-delta.js +25 -0
- package/dist/reports/src/evidence-detail.d.ts +64 -0
- package/dist/reports/src/evidence-detail.js +92 -0
- package/dist/reports/src/evidence-live.d.ts +35 -5
- package/dist/reports/src/evidence-live.js +18 -2
- package/dist/reports/src/evidence-types.d.ts +68 -1
- package/dist/reports/src/evidence-types.js +5 -1
- package/dist/reports/src/evidence-view.d.ts +43 -4
- package/dist/reports/src/evidence-view.js +13 -2
- package/dist/reports/src/explorer-types.d.ts +40 -3
- package/dist/reports/src/explorer-types.js +8 -0
- package/dist/reports/src/explorer-versions.d.ts +9 -1
- package/dist/reports/src/explorer-versions.js +18 -1
- package/dist/reports/src/export-evidence.d.ts +16 -1
- package/dist/reports/src/export-evidence.js +52 -1
- package/dist/reports/src/fetcher.d.ts +27 -3
- package/dist/reports/src/fetcher.js +11 -3
- package/dist/reports/src/format-date.d.ts +6 -0
- package/dist/reports/src/format-date.js +6 -0
- package/dist/reports/src/format.d.ts +16 -0
- package/dist/reports/src/format.js +10 -0
- package/dist/reports/src/frames.d.ts +36 -3
- package/dist/reports/src/frames.js +22 -3
- package/dist/reports/src/hash.d.ts +18 -0
- package/dist/reports/src/hash.js +13 -0
- package/dist/reports/src/host.d.ts +29 -0
- package/dist/reports/src/host.js +64 -0
- package/dist/reports/src/html-frame.d.ts +5 -6
- package/dist/reports/src/html-frame.js +12 -1
- package/dist/reports/src/http-store.d.ts +56 -0
- package/dist/reports/src/http-store.js +148 -0
- package/dist/reports/src/http.d.ts +7 -0
- package/dist/reports/src/http.js +6 -0
- package/dist/reports/src/ingest.d.ts +54 -0
- package/dist/reports/src/ingest.js +210 -0
- package/dist/reports/src/init.d.ts +40 -0
- package/dist/reports/src/init.js +369 -0
- package/dist/reports/src/junit.d.ts +33 -6
- package/dist/reports/src/junit.js +87 -21
- package/dist/reports/src/keyboard.d.ts +20 -0
- package/dist/reports/src/keyboard.js +11 -0
- package/dist/reports/src/keys.d.ts +21 -3
- package/dist/reports/src/keys.js +21 -3
- package/dist/reports/src/layer-axes.d.ts +35 -5
- package/dist/reports/src/layer-axes.js +25 -5
- package/dist/reports/src/layer-catalog.d.ts +28 -1
- package/dist/reports/src/layer-catalog.js +18 -1
- package/dist/reports/src/layer-merge.d.ts +98 -9
- package/dist/reports/src/layer-merge.js +147 -31
- package/dist/reports/src/layer-source.d.ts +18 -0
- package/dist/reports/src/layer-source.js +11 -0
- package/dist/reports/src/layer-store.d.ts +42 -0
- package/dist/reports/src/layer-store.js +63 -5
- package/dist/reports/src/layer-types.d.ts +32 -1
- package/dist/reports/src/layers-route.d.ts +47 -4
- package/dist/reports/src/layers-route.js +86 -7
- package/dist/reports/src/live-reporter.d.ts +34 -0
- package/dist/reports/src/live-reporter.js +122 -0
- package/dist/reports/src/media-types.d.ts +11 -0
- package/dist/reports/src/media-types.js +22 -0
- package/dist/reports/src/namespace-guard.d.ts +10 -1
- package/dist/reports/src/namespace-guard.js +10 -1
- package/dist/reports/src/navigation.d.ts +12 -0
- package/dist/reports/src/navigation.js +7 -0
- package/dist/reports/src/object-io.d.ts +11 -4
- package/dist/reports/src/object-io.js +4 -4
- package/dist/reports/src/object-store-conformance.d.ts +27 -0
- package/dist/reports/src/object-store-conformance.js +87 -0
- package/dist/reports/src/object-store.d.ts +33 -24
- package/dist/reports/src/object-store.js +17 -24
- package/dist/reports/src/parse-with.d.ts +16 -0
- package/dist/reports/src/parse-with.js +14 -0
- package/dist/reports/src/performance-part.d.ts +25 -1
- package/dist/reports/src/performance-part.js +15 -1
- package/dist/reports/src/performance.d.ts +22 -2
- package/dist/reports/src/performance.js +12 -2
- package/dist/reports/src/persist.d.ts +12 -3
- package/dist/reports/src/persist.js +12 -3
- package/dist/reports/src/phone.d.ts +18 -1
- package/dist/reports/src/phone.js +18 -1
- package/dist/reports/src/protocol.d.ts +26 -4
- package/dist/reports/src/protocol.js +15 -4
- package/dist/reports/src/publication.d.ts +21 -1
- package/dist/reports/src/publication.js +21 -1
- package/dist/reports/src/publish-checks.d.ts +35 -0
- package/dist/reports/src/publish-checks.js +122 -0
- package/dist/reports/src/publish.d.ts +42 -9
- package/dist/reports/src/publish.js +36 -7
- package/dist/reports/src/read.d.ts +46 -16
- package/dist/reports/src/read.js +38 -14
- package/dist/reports/src/recording-bundle.d.ts +13 -2
- package/dist/reports/src/recording-bundle.js +4 -2
- package/dist/reports/src/recording-keys.d.ts +15 -1
- package/dist/reports/src/recording-keys.js +15 -1
- package/dist/reports/src/remote-report.d.ts +28 -7
- package/dist/reports/src/remote-report.js +15 -7
- package/dist/reports/src/report-cli.d.ts +51 -0
- package/dist/reports/src/report-cli.js +486 -0
- package/dist/reports/src/report-index.d.ts +99 -0
- package/dist/reports/src/report-index.js +337 -0
- package/dist/reports/src/report-loader.d.ts +10 -0
- package/dist/reports/src/report-loader.js +6 -0
- package/dist/reports/src/report-parts.d.ts +29 -3
- package/dist/reports/src/report-parts.js +37 -3
- package/dist/reports/src/report-status.d.ts +48 -0
- package/dist/reports/src/report-status.js +156 -0
- package/dist/reports/src/report-types.d.ts +73 -0
- package/dist/reports/src/report-types.js +3 -0
- package/dist/reports/src/reporter.d.ts +67 -0
- package/dist/reports/src/reporter.js +128 -0
- package/dist/reports/src/reports-explorer-route.d.ts +541 -0
- package/dist/reports/src/reports-explorer-route.js +11 -0
- package/dist/reports/src/reports-list-route.d.ts +9 -0
- package/dist/reports/src/reports-list-route.js +9 -0
- package/dist/reports/src/reports-route.d.ts +561 -22
- package/dist/reports/src/reports-route.js +11 -3
- package/dist/reports/src/reports-store.d.ts +19 -2
- package/dist/reports/src/reports-store.js +10 -2
- package/dist/reports/src/resilient-cache.d.ts +14 -1
- package/dist/reports/src/resilient-cache.js +8 -1
- package/dist/reports/src/retention.d.ts +17 -1
- package/dist/reports/src/retention.js +5 -1
- package/dist/reports/src/run-bundle.d.ts +63 -0
- package/dist/reports/src/run-bundle.js +159 -0
- package/dist/reports/src/s3-store.d.ts +79 -0
- package/dist/reports/src/s3-store.js +295 -0
- package/dist/reports/src/scenario.d.ts +14 -4
- package/dist/reports/src/scenario.js +5 -4
- package/dist/reports/src/sigv4.d.ts +72 -0
- package/dist/reports/src/sigv4.js +96 -0
- package/dist/reports/src/snapshot-bundle.d.ts +24 -1
- package/dist/reports/src/snapshot-bundle.js +27 -2
- package/dist/reports/src/snapshot-surface.d.ts +20 -9
- package/dist/reports/src/snapshot-surface.js +32 -19
- package/dist/reports/src/source-content.d.ts +23 -0
- package/dist/reports/src/source-content.js +30 -1
- package/dist/reports/src/source-entries.d.ts +13 -0
- package/dist/reports/src/source-entries.js +6 -0
- package/dist/reports/src/source-part.d.ts +15 -0
- package/dist/reports/src/source-part.js +8 -0
- package/dist/reports/src/source-reader.d.ts +11 -0
- package/dist/reports/src/source-reader.js +5 -0
- package/dist/reports/src/spec-evidence.d.ts +12 -2
- package/dist/reports/src/spec-evidence.js +6 -2
- package/dist/reports/src/spec-inventory.d.ts +15 -1
- package/dist/reports/src/spec-inventory.js +22 -1
- package/dist/reports/src/spec-link.d.ts +28 -0
- package/dist/reports/src/spec-link.js +70 -0
- package/dist/reports/src/spec-set.d.ts +63 -0
- package/dist/reports/src/spec-set.js +177 -0
- package/dist/reports/src/status.d.ts +10 -0
- package/dist/reports/src/status.js +5 -0
- package/dist/reports/src/store-prefix.d.ts +28 -0
- package/dist/reports/src/store-prefix.js +22 -0
- package/dist/reports/src/store-url.d.ts +89 -0
- package/dist/reports/src/store-url.js +160 -0
- package/dist/reports/src/test-catalog-entity.d.ts +11 -0
- package/dist/reports/src/test-catalog-entity.js +6 -0
- package/dist/reports/src/types.d.ts +6 -1
- package/dist/reports/src/use-report-nav.d.ts +35 -0
- package/dist/reports/src/use-report-nav.js +12 -0
- package/dist/runners/src/codecept.d.ts +14 -0
- package/dist/runners/src/codecept.js +16 -0
- package/dist/runners/src/jest.d.ts +50 -0
- package/dist/runners/src/jest.js +52 -0
- package/dist/runners/src/mocha.d.ts +40 -0
- package/dist/runners/src/mocha.js +39 -0
- package/dist/runners/src/node-test.d.ts +28 -0
- package/dist/runners/src/node-test.js +44 -0
- package/dist/runners/src/publish.d.ts +30 -0
- package/dist/runners/src/publish.js +68 -0
- package/dist/schema/src/api.d.ts +800 -0
- package/dist/schema/src/api.js +201 -0
- package/dist/schema/src/cli-results.d.ts +210 -0
- package/dist/schema/src/cli-results.js +124 -0
- package/dist/schema/src/common.d.ts +53 -0
- package/dist/schema/src/common.js +42 -0
- package/dist/schema/src/index.d.ts +16 -0
- package/dist/schema/src/index.js +16 -0
- package/dist/schema/src/layer.d.ts +2273 -0
- package/dist/schema/src/layer.js +462 -0
- package/dist/schema/src/live-run.d.ts +123 -0
- package/dist/schema/src/live-run.js +30 -0
- package/dist/schema/src/manifest.d.ts +97 -2
- package/dist/schema/src/manifest.js +84 -0
- package/dist/schema/src/project.d.ts +20 -0
- package/dist/schema/src/project.js +10 -0
- package/dist/schema/src/report-sources.d.ts +29 -0
- package/dist/schema/src/report-sources.js +27 -1
- package/dist/schema/src/runs-index.d.ts +17 -1
- package/dist/schema/src/runs-index.js +15 -0
- package/dist/schema/src/server-config.d.ts +177 -0
- package/dist/schema/src/server-config.js +85 -0
- package/dist/schema/src/spec.d.ts +69 -0
- package/dist/schema/src/spec.js +58 -0
- package/dist/server/src/app.d.ts +72 -0
- package/dist/server/src/app.js +557 -0
- package/dist/server/src/auth.d.ts +41 -0
- package/dist/server/src/auth.js +59 -0
- package/dist/server/src/config.d.ts +83 -0
- package/dist/server/src/config.js +204 -0
- package/dist/server/src/dev.d.ts +12 -0
- package/dist/server/src/dev.js +89 -0
- package/dist/server/src/events.d.ts +29 -0
- package/dist/server/src/events.js +101 -0
- package/dist/server/src/host.d.ts +30 -0
- package/dist/server/src/host.js +115 -0
- package/dist/server/src/index.d.ts +18 -0
- package/dist/server/src/index.js +18 -0
- package/dist/server/src/live-runs.d.ts +52 -0
- package/dist/server/src/live-runs.js +229 -0
- package/dist/server/src/llms.d.ts +19 -0
- package/dist/server/src/llms.js +63 -0
- package/dist/server/src/main.d.ts +30 -0
- package/dist/server/src/main.js +114 -0
- package/dist/server/src/openapi.d.ts +56 -0
- package/dist/server/src/openapi.js +438 -0
- package/dist/server/src/problem.d.ts +8 -0
- package/dist/server/src/problem.js +39 -0
- package/dist/server/src/projects.d.ts +3 -0
- package/dist/server/src/projects.js +154 -0
- package/dist/server/src/settings-page.d.ts +9 -0
- package/dist/server/src/settings-page.js +93 -0
- package/dist/server/src/settings.d.ts +23 -0
- package/dist/server/src/settings.js +72 -0
- package/dist/server/src/site.d.ts +15 -0
- package/dist/server/src/site.js +78 -0
- package/dist/server/src/store-api.d.ts +28 -0
- package/dist/server/src/store-api.js +180 -0
- package/dist/server/src/validate.d.ts +71 -0
- package/dist/server/src/validate.js +197 -0
- package/dist/vitest/src/index.d.ts +27 -5
- package/dist/vitest/src/index.js +18 -5
- package/dist/webdriver/src/driver.d.ts +63 -11
- package/dist/webdriver/src/driver.js +57 -6
- package/dist/webdriver/src/index.d.ts +8 -0
- package/dist/webdriver/src/index.js +1 -0
- package/dist/webdriver/src/protocol.d.ts +75 -6
- package/dist/webdriver/src/protocol.js +79 -6
- package/docs/agents.md +137 -0
- package/docs/deploying.md +345 -0
- package/docs/dogfooding.md +175 -0
- package/docs/extending.md +242 -0
- package/docs/integrating.md +485 -0
- package/docs/reference/bun.md +141 -0
- package/docs/reference/cli.md +148 -0
- package/docs/reference/core.md +2432 -0
- package/docs/reference/detox.md +150 -0
- package/docs/reference/http-api.md +799 -0
- package/docs/reference/playwright.md +303 -0
- package/docs/reference/reports.md +7152 -0
- package/docs/reference/runners.md +169 -0
- package/docs/reference/schema.md +1762 -0
- package/docs/reference/server.md +825 -0
- package/docs/reference/vitest.md +45 -0
- package/docs/reference/webdriver.md +330 -0
- package/docs/report-backends.md +144 -0
- package/docs/report-contract.md +400 -0
- package/docs/reporting-issues.md +160 -0
- package/docs/runners.md +69 -0
- package/docs/server.md +321 -0
- package/docs/statecharts.md +643 -0
- package/llms-full.txt +4114 -0
- package/llms.txt +49 -0
- package/package.json +61 -11
- package/packages/core/README.md +2 -1
- package/packages/reports/README.md +65 -0
- package/packages/reports/STORAGE.md +4 -0
- package/packages/runners/README.md +6 -0
- package/packages/runners/compat/codecept.cjs +2 -0
- package/packages/runners/compat/jest.cjs +2 -0
- package/packages/runners/compat/mocha.cjs +2 -0
- package/packages/schema/README.md +14 -0
- package/packages/schema/schemas/atlas-change.schema.json +4 -0
- package/packages/schema/schemas/check-detail.schema.json +1032 -0
- package/packages/schema/schemas/checks-result.schema.json +26 -0
- package/packages/schema/schemas/command-error.schema.json +35 -0
- package/packages/schema/schemas/doctor-result.schema.json +60 -0
- package/packages/schema/schemas/effective-delta.schema.json +490 -0
- package/packages/schema/schemas/effective-evidence.schema.json +471 -0
- package/packages/schema/schemas/evidence-page.schema.json +271 -0
- package/packages/schema/schemas/hello-event.schema.json +26 -0
- package/packages/schema/schemas/init-plan.schema.json +347 -0
- package/packages/schema/schemas/layer-rows.schema.json +199 -0
- package/packages/schema/schemas/layer.schema.json +2888 -0
- package/packages/schema/schemas/live-run-start.schema.json +42 -0
- package/packages/schema/schemas/live-run-update.schema.json +93 -0
- package/packages/schema/schemas/live-run.schema.json +225 -0
- package/packages/schema/schemas/merge-result.schema.json +40 -0
- package/packages/schema/schemas/outline.schema.json +62 -0
- package/packages/schema/schemas/problem.schema.json +37 -0
- package/packages/schema/schemas/project-slug.schema.json +8 -0
- package/packages/schema/schemas/project.schema.json +22 -0
- package/packages/schema/schemas/projects.schema.json +33 -0
- package/packages/schema/schemas/publish-checks.schema.json +1413 -0
- package/packages/schema/schemas/publish-result.schema.json +168 -0
- package/packages/schema/schemas/ready.schema.json +68 -0
- package/packages/schema/schemas/report-event.schema.json +100 -0
- package/packages/schema/schemas/report-status.schema.json +370 -0
- package/packages/schema/schemas/server-config.schema.json +208 -0
- package/packages/schema/schemas/server-editable-settings.schema.json +132 -0
- package/packages/schema/schemas/server-info.schema.json +114 -0
- package/packages/schema/schemas/server-settings-snapshot.schema.json +285 -0
- package/packages/schema/schemas/spec-set.schema.json +103 -0
- package/packages/schema/schemas/store-listing.schema.json +29 -0
- package/packages/schema/schemas/store-write-result.schema.json +28 -0
- package/packages/schema/schemas/stream-result.schema.json +59 -0
- package/packages/server/README.md +43 -0
- package/packages/server/openapi.json +11021 -0
- package/packages/visualizer/README.md +32 -11
- package/packages/visualizer/bin/atlas-client.mjs +176 -0
- package/packages/visualizer/bin/atlas-visualizer.mjs +2 -175
- package/packages/visualizer/src/app/AppShell.tsx +32 -16
- package/packages/visualizer/src/app/report-sources.tsx +7 -4
- package/packages/visualizer/src/app/router.tsx +3 -3
- package/packages/visualizer/src/components/ActivityIndicator.module.css +4 -0
- package/packages/visualizer/src/components/ActivityIndicator.tsx +6 -0
- package/packages/visualizer/src/components/Header.module.css +101 -192
- package/packages/visualizer/src/components/Header.tsx +88 -13
- package/packages/visualizer/src/components/ProjectPicker.tsx +64 -0
- package/packages/visualizer/src/data/adapters/adapter.ts +5 -17
- package/packages/visualizer/src/data/adapters/index.ts +10 -1
- package/packages/visualizer/src/data/adapters/report-backend.test.ts +3 -2
- package/packages/visualizer/src/data/adapters/report-backend.ts +1 -1
- package/packages/visualizer/src/data/queries.ts +14 -7
- package/packages/visualizer/src/evidence/api.ts +16 -3
- package/packages/visualizer/src/evidence/artifacts.module.css +213 -0
- package/packages/visualizer/src/evidence/artifacts.tsx +272 -0
- package/packages/visualizer/src/evidence/check-detail.tsx +21 -4
- package/packages/visualizer/src/evidence/document-page.tsx +6 -2
- package/packages/visualizer/src/evidence/evidence-context.tsx +79 -12
- package/packages/visualizer/src/evidence/evidence.module.css +11 -1
- package/packages/visualizer/src/evidence/feature-page.tsx +7 -3
- package/packages/visualizer/src/evidence/model-page.tsx +6 -2
- package/packages/visualizer/src/evidence/project-home.tsx +45 -0
- package/packages/visualizer/src/evidence/recording-page.tsx +4 -1
- package/packages/visualizer/src/evidence/spec-index.tsx +2 -1
- package/packages/visualizer/src/evidence/spec-page.tsx +23 -16
- package/packages/visualizer/src/evidence/test-filter.tsx +21 -0
- package/packages/visualizer/src/find/Finder.tsx +1 -7
- package/packages/visualizer/src/find/open.ts +4 -0
- package/packages/visualizer/src/live/live-query.ts +21 -0
- package/packages/visualizer/src/live/live-runs.tsx +69 -0
- package/packages/visualizer/src/live/live-stream.ts +225 -0
- package/packages/visualizer/src/live/report-progress.ts +62 -0
- package/packages/visualizer/src/live/test-progress.tsx +34 -0
- package/packages/visualizer/src/runtime.ts +35 -0
- package/packages/visualizer/src/state/ui-store.ts +3 -2
- package/packages/visualizer/src/views/ChartPage.tsx +2 -0
- package/packages/visualizer/src/views/ChartTests.tsx +43 -0
- package/packages/visualizer/src/views/SidePanel.tsx +2 -0
- package/packages/visualizer/vite/atlas-files.test.ts +4 -4
- package/packages/visualizer/vite/atlas-files.ts +1 -5
- package/packages/visualizer/vite/atlas-server-proxy.ts +37 -0
- 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
|
-
*
|
|
49
|
-
* recognised when every `all` is visible, one `any` is visible and no `none` is
|
|
50
|
-
*
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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 = {
|
package/dist/core/src/signals.js
CHANGED
|
@@ -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
|
-
*
|
|
19
|
-
* recognised when every `all` is visible, one `any` is visible and no `none` is
|
|
20
|
-
*
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
*
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
*
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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 ?? {}))
|