waygraph 0.15.54 → 0.16.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/README.md +8 -3
- package/bin/waygraph +2 -2
- package/dist/analysis/check.d.ts +38 -0
- package/dist/analysis/check.js +87 -0
- package/dist/analysis/coverage-gap.d.ts +1 -1
- package/dist/analysis/coverage-gap.js +14 -37
- package/dist/analysis/flow-source.d.ts +9 -0
- package/dist/analysis/flow-source.js +25 -0
- package/dist/analysis/graph.d.ts +10 -14
- package/dist/analysis/graph.js +48 -371
- package/dist/analysis/map-check.js +4 -39
- package/dist/analysis/practices-check.d.ts +1 -1
- package/dist/analysis/practices-check.js +24 -45
- package/dist/cli/args.d.ts +23 -0
- package/dist/cli/args.js +20 -0
- package/dist/{cli.d.ts → cli/cli.d.ts} +0 -1
- package/dist/{cli.js → cli/cli.js} +10 -9
- package/dist/{commands → cli/commands}/agent-dive-scaffold.js +35 -64
- package/dist/cli/commands/agent-dive.js +42 -0
- package/dist/{commands → cli/commands}/check.d.ts +0 -1
- package/dist/cli/commands/check.js +104 -0
- package/dist/cli/commands/codemod-checkpoints.d.ts +18 -0
- package/dist/cli/commands/codemod-checkpoints.js +186 -0
- package/dist/cli/commands/codemod-flows.d.ts +18 -0
- package/dist/cli/commands/codemod-flows.js +284 -0
- package/dist/cli/commands/codemod-stubs.d.ts +10 -0
- package/dist/cli/commands/codemod-stubs.js +187 -0
- package/dist/{commands → cli/commands}/extensions.js +5 -4
- package/dist/{commands → cli/commands}/init.js +1 -2
- package/dist/{commands → cli/commands}/list.js +9 -7
- package/dist/cli/commands/manifest.d.ts +2 -0
- package/dist/cli/commands/manifest.js +20 -0
- package/dist/cli/commands/map.js +57 -0
- package/dist/{commands → cli/commands}/run.d.ts +0 -1
- package/dist/cli/commands/run.js +64 -0
- package/dist/{commands → cli/commands}/session.js +61 -88
- package/dist/{commands → cli/commands}/test.js +11 -14
- package/dist/cli/commands/traverse.js +105 -0
- package/dist/{commands → cli/commands}/try.js +29 -25
- package/dist/{commands → cli/commands}/upgrade.js +40 -4
- package/dist/cli/flags.d.ts +193 -16
- package/dist/cli/flags.js +179 -234
- package/dist/cli/run-chain.d.ts +1 -0
- package/dist/cli/run-chain.js +42 -7
- package/dist/cli/usage.d.ts +1 -1
- package/dist/cli/usage.js +21 -53
- package/dist/cli/util.d.ts +2 -2
- package/dist/cli/util.js +2 -3
- package/dist/{highlights → demo/narration}/css.d.ts +1 -1
- package/dist/{highlights → demo/narration}/css.js +2 -3
- package/dist/{highlights → demo/narration}/demo-pace.d.ts +3 -11
- package/dist/{highlights → demo/narration}/demo-pace.js +5 -11
- package/dist/{highlights → demo/narration}/device.d.ts +2 -2
- package/dist/{highlights → demo/narration}/device.js +1 -1
- package/dist/demo/narration/merge.d.ts +8 -0
- package/dist/demo/narration/merge.js +71 -0
- package/dist/{highlights/run-phase.d.ts → demo/narration/narration.d.ts} +10 -14
- package/dist/{highlights/run-phase.js → demo/narration/narration.js} +25 -94
- package/dist/{highlights → demo/narration}/shorthand.d.ts +1 -1
- package/dist/demo/narration/stub-ctx.d.ts +8 -0
- package/dist/demo/narration/stub-ctx.js +164 -0
- package/dist/{highlights → demo/narration}/style.d.ts +1 -7
- package/dist/{highlights → demo/narration}/style.js +1 -41
- package/dist/{highlights → demo/narration}/todo-dock.d.ts +3 -3
- package/dist/{highlights → demo/narration}/todo-dock.js +13 -30
- package/dist/demo/overlay/auto-chrome.d.ts +7 -0
- package/dist/demo/overlay/auto-chrome.js +97 -0
- package/dist/demo/overlay/cursor.d.ts +12 -0
- package/dist/demo/overlay/cursor.js +142 -0
- package/dist/demo/overlay/device-stage.d.ts +13 -0
- package/dist/demo/overlay/device-stage.js +396 -0
- package/dist/demo/overlay/inpage/banner.d.ts +1 -0
- package/dist/demo/overlay/inpage/banner.js +160 -0
- package/dist/demo/overlay/inpage/caption.d.ts +2 -0
- package/dist/demo/overlay/inpage/caption.js +24 -0
- package/dist/demo/overlay/inpage/core.d.ts +1 -0
- package/dist/demo/overlay/inpage/core.js +345 -0
- package/dist/demo/overlay/inpage/device-chip.d.ts +1 -0
- package/dist/demo/overlay/inpage/device-chip.js +191 -0
- package/dist/demo/overlay/inpage/network.d.ts +9 -0
- package/dist/demo/overlay/inpage/network.js +200 -0
- package/dist/demo/overlay/inpage/panel-chrome.d.ts +1 -0
- package/dist/demo/overlay/inpage/panel-chrome.js +203 -0
- package/dist/demo/overlay/inpage/stamp.d.ts +1 -0
- package/dist/demo/overlay/inpage/stamp.js +46 -0
- package/dist/demo/overlay/inpage/swipe-zoom.d.ts +1 -0
- package/dist/demo/overlay/inpage/swipe-zoom.js +220 -0
- package/dist/demo/overlay/inpage/todos.d.ts +1 -0
- package/dist/demo/overlay/inpage/todos.js +294 -0
- package/dist/demo/overlay/locator-theater.d.ts +25 -0
- package/dist/demo/overlay/locator-theater.js +76 -0
- package/dist/demo/overlay/network-capture.d.ts +22 -0
- package/dist/demo/overlay/network-capture.js +127 -0
- package/dist/demo/overlay/overlay-css.d.ts +3 -0
- package/dist/demo/overlay/overlay-css.js +369 -0
- package/dist/demo/overlay/overlay-stage.d.ts +23 -0
- package/dist/demo/overlay/overlay-stage.js +106 -0
- package/dist/demo/overlay/overlay.d.ts +10 -0
- package/dist/demo/overlay/overlay.js +89 -0
- package/dist/{pilot-overlay/overlay-fixtures.d.ts → demo/overlay/phase-fixtures.d.ts} +2 -2
- package/dist/{pilot-overlay/overlay-fixtures.js → demo/overlay/phase-fixtures.js} +2 -2
- package/dist/{pilot-overlay/action-ring.js → demo/overlay/pilot/actions.js} +2 -1
- package/dist/{pilot-overlay → demo/overlay/pilot}/fixtures.d.ts +6 -5
- package/dist/{pilot-overlay → demo/overlay/pilot}/fixtures.js +19 -18
- package/dist/{pilot-overlay → demo/overlay/pilot}/shell.d.ts +2 -2
- package/dist/{pilot-overlay → demo/overlay/pilot}/shell.js +13 -22
- package/dist/demo/overlay/reattach.d.ts +7 -0
- package/dist/demo/overlay/reattach.js +23 -0
- package/dist/demo/overlay/rings.d.ts +33 -0
- package/dist/demo/overlay/rings.js +448 -0
- package/dist/{ui → demo/overlay/ui}/components/ring.js +2 -2
- package/dist/{ui → demo/overlay/ui}/overlay.css +4 -4
- package/dist/{ui → demo/overlay/ui}/shadow.d.ts +1 -1
- package/dist/{ui → demo/overlay/ui}/shadow.js +39 -2
- package/dist/demo/stepper/after.d.ts +3 -0
- package/dist/demo/stepper/after.js +113 -0
- package/dist/demo/stepper/banner-log.d.ts +37 -0
- package/dist/demo/stepper/banner-log.js +63 -0
- package/dist/demo/stepper/before.d.ts +4 -0
- package/dist/demo/stepper/before.js +110 -0
- package/dist/demo/stepper/demo-log.d.ts +31 -0
- package/dist/demo/stepper/demo-log.js +309 -0
- package/dist/demo/stepper/gate.d.ts +11 -0
- package/dist/demo/stepper/gate.js +78 -0
- package/dist/demo/stepper/interaction-patch.d.ts +3 -0
- package/dist/demo/stepper/interaction-patch.js +323 -0
- package/dist/demo/stepper/pacing.d.ts +21 -0
- package/dist/demo/stepper/pacing.js +23 -0
- package/dist/demo/stepper/slides.d.ts +11 -0
- package/dist/demo/stepper/slides.js +233 -0
- package/dist/demo/stepper/step-panels.d.ts +21 -0
- package/dist/demo/stepper/step-panels.js +589 -0
- package/dist/demo/stepper/stepper.d.ts +24 -0
- package/dist/demo/stepper/stepper.js +122 -0
- package/dist/demo/stepper/teardown.d.ts +48 -0
- package/dist/demo/stepper/teardown.js +179 -0
- package/dist/demo/stepper/todo-advance.d.ts +14 -0
- package/dist/demo/stepper/todo-advance.js +110 -0
- package/dist/demo/stepper/view.d.ts +68 -0
- package/dist/demo/stepper/view.js +31 -0
- package/dist/demo/types.d.ts +17 -0
- package/dist/demo/verbose-log.js +15 -0
- package/dist/{types.d.ts → engine/block/block.d.ts} +106 -91
- package/dist/{core → engine/block}/block.js +10 -53
- package/dist/{core → engine/block}/compose.d.ts +9 -7
- package/dist/{core → engine/block}/compose.js +1 -1
- package/dist/{core/blocks → engine/block/kinds}/api.d.ts +16 -12
- package/dist/{core/blocks → engine/block/kinds}/api.js +26 -18
- package/dist/{core/blocks → engine/block/kinds}/effect.d.ts +13 -18
- package/dist/engine/block/kinds/effect.js +17 -0
- package/dist/{core/blocks → engine/block/kinds}/method.d.ts +17 -29
- package/dist/{core/blocks → engine/block/kinds}/method.js +6 -21
- package/dist/{core/blocks → engine/block/kinds}/nav.d.ts +21 -31
- package/dist/{core/blocks → engine/block/kinds}/nav.js +6 -12
- package/dist/{core/blocks → engine/block/kinds}/page.d.ts +14 -20
- package/dist/{core/blocks → engine/block/kinds}/page.js +5 -7
- package/dist/engine/checkpoint/checkpoint.d.ts +22 -0
- package/dist/engine/checkpoint/checkpoint.js +8 -0
- package/dist/engine/checkpoint/route.d.ts +28 -0
- package/dist/engine/checkpoint/route.js +28 -0
- package/dist/{core → engine}/config.d.ts +7 -2
- package/dist/engine/config.js +6 -0
- package/dist/engine/engine.d.ts +45 -0
- package/dist/{core → engine}/engine.js +6 -10
- package/dist/engine/env.d.ts +59 -0
- package/dist/engine/env.js +83 -0
- package/dist/{errors.d.ts → engine/errors.d.ts} +22 -22
- package/dist/{errors.js → engine/errors.js} +22 -22
- package/dist/{core → engine/flow}/branch-regression.d.ts +7 -7
- package/dist/{core → engine/flow}/branch-regression.js +4 -3
- package/dist/engine/flow/flow.d.ts +162 -0
- package/dist/engine/flow/flow.js +244 -0
- package/dist/{core → engine/flow}/map-builder.d.ts +34 -39
- package/dist/{core → engine/flow}/map-builder.js +45 -47
- package/dist/{core → engine}/locate.d.ts +1 -1
- package/dist/{core → engine}/locate.js +1 -2
- package/dist/{mem-stub.d.ts → engine/mem/mem-stub.d.ts} +9 -8
- package/dist/{mem-stub.js → engine/mem/mem-stub.js} +2 -2
- package/dist/{mem-page.d.ts → engine/mem/mem.d.ts} +1 -1
- package/dist/{mem-page.js → engine/mem/mem.js} +2 -1
- package/dist/engine/page-gone.d.ts +5 -0
- package/dist/engine/page-gone.js +20 -0
- package/dist/engine/run/connect.d.ts +28 -0
- package/dist/{types.js → engine/run/connect.js} +11 -10
- package/dist/engine/run/events.d.ts +67 -0
- package/dist/engine/run/events.js +90 -0
- package/dist/engine/run/hooks.d.ts +16 -0
- package/dist/engine/run/hooks.js +8 -0
- package/dist/engine/run/launch.d.ts +13 -0
- package/dist/engine/run/launch.js +27 -0
- package/dist/{core/run-graph.d.ts → engine/run/run.d.ts} +8 -12
- package/dist/{core/run-graph.js → engine/run/run.js} +22 -12
- package/dist/engine/stub/pace.d.ts +12 -0
- package/dist/engine/stub/pace.js +2 -0
- package/dist/engine/stub/ring.d.ts +130 -0
- package/dist/engine/stub/ring.js +41 -0
- package/dist/engine/stub/stub.d.ts +268 -0
- package/dist/engine/stub/stub.js +1 -0
- package/dist/engine/stub/todos.d.ts +104 -0
- package/dist/engine/stub/todos.js +2 -0
- package/dist/engine/stub/viewport.d.ts +26 -0
- package/dist/engine/stub/viewport.js +2 -0
- package/dist/{trait.d.ts → engine/trait/trait.d.ts} +1 -1
- package/dist/index.d.ts +84 -36
- package/dist/index.js +44 -19
- package/dist/{session/auto-explore-run.d.ts → live/auto/auto.d.ts} +10 -16
- package/dist/{session/auto-explore-run.js → live/auto/auto.js} +164 -254
- package/dist/{session/auto-explore.d.ts → live/auto/explore.d.ts} +4 -14
- package/dist/{session/auto-explore.js → live/auto/explore.js} +21 -127
- package/dist/{auto-session/session.d.ts → live/auto-session/auto-session.d.ts} +1 -1
- package/dist/{auto-session/session.js → live/auto-session/auto-session.js} +27 -24
- package/dist/{auto-session → live/auto-session}/helpers.d.ts +6 -5
- package/dist/{auto-session → live/auto-session}/helpers.js +1 -1
- package/dist/{session/auto-session-ipc.d.ts → live/auto-session/ipc.d.ts} +7 -5
- package/dist/{session/auto-session-ipc.js → live/auto-session/ipc.js} +31 -16
- package/dist/{session/browser.d.ts → live/auto-session/start.d.ts} +1 -2
- package/dist/{session/browser.js → live/auto-session/start.js} +2 -3
- package/dist/{pilot-overlay → live/pilot}/panel.d.ts +1 -1
- package/dist/{pilot-overlay → live/pilot}/panel.js +23 -31
- package/dist/{session → live/pilot}/pilot.d.ts +3 -3
- package/dist/{session → live/pilot}/pilot.js +4 -4
- package/dist/{traverse/run.d.ts → live/traverse/traverse.d.ts} +1 -1
- package/dist/{traverse/run.js → live/traverse/traverse.js} +26 -43
- package/dist/manifest/manifest.d.ts +52 -0
- package/dist/manifest/manifest.js +93 -0
- package/dist/manifest/map-imports.d.ts +7 -0
- package/dist/manifest/map-imports.js +22 -0
- package/dist/manifest/maps.d.ts +33 -0
- package/dist/manifest/maps.js +62 -0
- package/dist/manifest/pack.d.ts +21 -0
- package/dist/manifest/pack.js +109 -0
- package/dist/manifest/project.d.ts +60 -0
- package/dist/manifest/project.js +101 -0
- package/dist/{session/block-inject.js → manifest/roots.js} +1 -18
- package/dist/manifest/scan.d.ts +19 -0
- package/dist/manifest/scan.js +57 -0
- package/dist/manifest/source.d.ts +23 -0
- package/dist/manifest/source.js +86 -0
- package/dist/runner/mode.d.ts +71 -0
- package/dist/runner/mode.js +1 -0
- package/dist/runner/modes/branches.d.ts +5 -0
- package/dist/runner/modes/branches.js +37 -0
- package/dist/runner/modes/demo.d.ts +3 -0
- package/dist/runner/modes/demo.js +13 -0
- package/dist/runner/modes/report.d.ts +2 -0
- package/dist/runner/modes/report.js +54 -0
- package/dist/runner/modes/run.d.ts +2 -0
- package/dist/runner/modes/run.js +3 -0
- package/dist/runner/options.d.ts +31 -0
- package/dist/runner/options.js +42 -0
- package/dist/runner/plan/find.d.ts +18 -0
- package/dist/runner/plan/find.js +65 -0
- package/dist/runner/plan/plan.d.ts +11 -0
- package/dist/runner/plan/plan.js +97 -0
- package/dist/runner/plan/seed-mem.d.ts +12 -0
- package/dist/runner/plan/seed-mem.js +98 -0
- package/dist/runner/plan/spec.d.ts +5 -0
- package/dist/runner/plan/spec.js +17 -0
- package/dist/runner/play-steps.d.ts +2 -0
- package/dist/runner/play-steps.js +59 -0
- package/dist/runner/runner.d.ts +4 -0
- package/dist/runner/runner.js +64 -0
- package/dist/runner/session.d.ts +9 -0
- package/dist/runner/session.js +87 -0
- package/dist/{browser.js → runtime/browser.js} +4 -2
- package/dist/{env-file.js → runtime/env-file.js} +7 -12
- package/dist/{extensions.d.ts → runtime/extensions.d.ts} +1 -5
- package/dist/{extensions.js → runtime/extensions.js} +2 -1
- package/dist/runtime/full-launch.d.ts +1 -0
- package/dist/runtime/full-launch.js +34 -0
- package/dist/runtime/global-flag.d.ts +5 -0
- package/dist/runtime/global-flag.js +18 -0
- package/dist/{playwright-config.d.ts → runtime/playwright-config.d.ts} +1 -1
- package/dist/{playwright.config.js → runtime/playwright.config.js} +3 -2
- package/dist/runtime/run-log.d.ts +2 -0
- package/dist/runtime/run-log.js +17 -0
- package/dist/{video-dir.js → runtime/video-dir.js} +3 -2
- package/dist/{config.d.ts → runtime/waygraph-config.d.ts} +6 -9
- package/dist/{config.js → runtime/waygraph-config.js} +21 -51
- package/dist/{webserver.js → runtime/webserver.js} +5 -30
- package/examples/routed-demo/config/waygraph.config.ts +20 -0
- package/examples/routed-demo/package.json +1 -4
- package/examples/routed-demo/scripts/fixture-server.mjs +1 -1
- package/examples/routed-demo/src/flows/routed-demo-map.flow.ts +2 -4
- package/examples/routed-demo/src/flows/routed-demo.flow.ts +1 -2
- package/examples/routed-demo/src/map/(app_base)/dashboard/_methods/click-widget.block.ts +5 -4
- package/examples/routed-demo/src/map/(app_base)/dashboard/_nav.block.ts +3 -3
- package/examples/routed-demo/src/map/(app_base)/dashboard/_page.block.ts +3 -3
- package/examples/routed-demo/src/map/(external)/docs/_nav.block.ts +3 -3
- package/examples/routed-demo/src/map/(external)/docs/_page.block.ts +3 -3
- package/examples/routed-demo/src/states/routed-demo.states.ts +5 -3
- package/examples/routed-demo/tests/routed-demo.spec.ts +4 -4
- package/examples/routed-demo/tsconfig.json +1 -1
- package/examples/saucedemo/docs/CONVENTION.md +4 -5
- package/examples/saucedemo/docs/HELPERS.md +11 -11
- package/examples/saucedemo/src/blocks/SITE-MAP.md +0 -1
- package/examples/saucedemo/src/blocks/saucedemo-web/NAV.md +1 -5
- package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-cart.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-checkout-info.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-first-name.method.block.ts +5 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-last-name.method.block.ts +5 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-postal-code.method.block.ts +5 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.ts +5 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +5 -8
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/inventory.page.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/add-all-to-cart.method.block.ts +4 -6
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +35 -43
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/remove-all-from-cart.method.block.ts +4 -6
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/remove-from-cart.effect.block.ts +4 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/nav-item-detail.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +5 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +5 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +4 -5
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-logout.method.block.ts +5 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/nav-login.block.ts +3 -3
- package/examples/saucedemo/src/flows/api-demo.flow.ts +12 -10
- package/examples/saucedemo/src/states/checkout.states.ts +21 -11
- package/examples/saucedemo/src/stubs/device-showcase.ts +8 -10
- package/examples/saucedemo/tests/auto-graph.spec.ts +4 -12
- package/package.json +10 -6
- package/templates/agents/waygraph-planner.agent.md +2 -2
- package/templates/quickstart/docs/CONVENTION.md +4 -4
- package/templates/quickstart/docs/HELPERS.md +10 -8
- package/templates/quickstart/package.json +0 -3
- package/templates/quickstart/src/blocks/SITE-MAP.md +0 -1
- package/templates/quickstart/src/blocks/saucedemo-web/NAV.md +1 -5
- package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-cart.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-checkout-info.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-first-name.method.block.ts +5 -4
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-last-name.method.block.ts +5 -4
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-postal-code.method.block.ts +5 -4
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.ts +5 -4
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +5 -8
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/inventory.page.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-all-to-cart.method.block.ts +4 -6
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +35 -43
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/remove-all-from-cart.method.block.ts +4 -6
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/remove-from-cart.effect.block.ts +4 -3
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/nav-item-detail.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +5 -4
- package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +5 -4
- package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +4 -5
- package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-logout.method.block.ts +5 -4
- package/templates/quickstart/src/blocks/saucedemo-web/nav-login.block.ts +3 -3
- package/templates/quickstart/src/flows/api-demo.flow.ts +12 -10
- package/templates/quickstart/src/states/checkout.states.ts +21 -11
- package/templates/quickstart/src/stubs/device-showcase.ts +8 -10
- package/templates/scaffold/README.md +2 -1
- package/templates/scaffold/STRUCTURE.md +5 -4
- package/templates/scaffold/config/waygraph.config.ts +1 -0
- package/templates/scaffold/gitignore +1 -0
- package/templates/scaffold/src/flows/README.md +2 -2
- package/templates/scaffold/src/map/(app_base)/docs/_nav.block.ts +3 -3
- package/templates/scaffold/src/map/(app_base)/docs/_page.block.ts +3 -3
- package/templates/scaffold/src/map/(app_base)/home/_methods/add-item.effect.block.ts +4 -4
- package/templates/scaffold/src/map/(app_base)/home/_methods/assert-hello.method.block.ts +3 -3
- package/templates/scaffold/src/map/(app_base)/home/_methods/assert-item-added.method.block.ts +3 -3
- package/templates/scaffold/src/map/(app_base)/home/_methods/clear-cart.method.block.ts +5 -4
- package/templates/scaffold/src/map/(app_base)/home/_methods/remove-item.effect.block.ts +4 -4
- package/templates/scaffold/src/map/(app_base)/home/_nav.block.ts +3 -3
- package/templates/scaffold/src/map/(app_base)/home/_page.block.ts +3 -3
- package/templates/scaffold/src/map/(app_base)/home/nav-verification-link.block.ts +4 -4
- package/templates/scaffold/src/map/(external)/hoppscotch/_keys.ts +21 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-response-body.method.block.ts +4 -4
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-response-header.method.block.ts +4 -4
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-status.method.block.ts +4 -4
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/pick-extension-interceptor.method.block.ts +5 -4
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/read-response-body.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/read-response-headers.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/send-request.method.block.ts +5 -4
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-bearer-token.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-headers.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-json-body.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-method.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-query-params.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-url.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/hoppscotch/_nav.block.ts +3 -3
- package/templates/scaffold/src/map/(external)/hoppscotch/_page.block.ts +3 -3
- package/templates/scaffold/src/map/(external)/hoppscotch/_states.ts +6 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/settings/_nav.block.ts +3 -3
- package/templates/scaffold/src/map/(external)/mailpit/_keys.ts +13 -0
- package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-content.method.block.ts +4 -4
- package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-received.method.block.ts +4 -4
- package/templates/scaffold/src/map/(external)/mailpit/_methods/extract-email-link.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/mailpit/_methods/open-message.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/mailpit/_nav.block.ts +3 -3
- package/templates/scaffold/src/map/(external)/mailpit/_page.block.ts +3 -3
- package/templates/scaffold/src/map/(external)/mailpit/_states.ts +9 -0
- package/templates/scaffold/src/map/README.md +7 -0
- package/templates/scaffold/src/states/README.md +4 -1
- package/templates/scaffold/src/states/demo.mem-keys.ts +1 -29
- package/templates/scaffold/src/states/demo.states.ts +14 -20
- package/templates/scaffold/tests/hoppscotch.spec.ts +1 -11
- package/templates/scaffold/tests/mail-verify.spec.ts +2 -2
- package/templates/skills/waygraph-blind-pilot.skill.md +2 -6
- package/templates/skills/waygraph-convention.skill.md +23 -14
- package/templates/skills/waygraph-pilot.skill.md +7 -4
- package/dist/auto-session/verbose-log.js +0 -16
- package/dist/auto-session.d.ts +0 -2
- package/dist/auto-session.js +0 -3
- package/dist/cli/discover.d.ts +0 -40
- package/dist/cli/discover.js +0 -148
- package/dist/commands/agent-dive.js +0 -52
- package/dist/commands/check.js +0 -192
- package/dist/commands/map.js +0 -29
- package/dist/commands/run.js +0 -104
- package/dist/commands/traverse.js +0 -177
- package/dist/core/block.d.ts +0 -109
- package/dist/core/blocks/effect.js +0 -23
- package/dist/core/config.js +0 -17
- package/dist/core/engine.d.ts +0 -198
- package/dist/core/flow.d.ts +0 -294
- package/dist/core/flow.js +0 -432
- package/dist/core.d.ts +0 -14
- package/dist/core.js +0 -15
- package/dist/highlights/merge.d.ts +0 -8
- package/dist/highlights/merge.js +0 -173
- package/dist/highlights/stub-ctx.d.ts +0 -10
- package/dist/highlights/stub-ctx.js +0 -331
- package/dist/highlights/types.d.ts +0 -613
- package/dist/highlights.d.ts +0 -9
- package/dist/highlights.js +0 -10
- package/dist/pilot-overlay.d.ts +0 -5
- package/dist/pilot-overlay.js +0 -6
- package/dist/runner/banner-log.js +0 -63
- package/dist/runner/chain-run.js +0 -102
- package/dist/runner/cursor.js +0 -140
- package/dist/runner/demo-log.js +0 -316
- package/dist/runner/device-stage.d.ts +0 -9
- package/dist/runner/device-stage.js +0 -420
- package/dist/runner/discovery.js +0 -105
- package/dist/runner/index.js +0 -2
- package/dist/runner/inpage/banner.d.ts +0 -21
- package/dist/runner/inpage/banner.js +0 -156
- package/dist/runner/inpage/caption.d.ts +0 -3
- package/dist/runner/inpage/caption.js +0 -23
- package/dist/runner/inpage/core.d.ts +0 -4
- package/dist/runner/inpage/core.js +0 -316
- package/dist/runner/inpage/device.d.ts +0 -3
- package/dist/runner/inpage/device.js +0 -211
- package/dist/runner/inpage/network.d.ts +0 -15
- package/dist/runner/inpage/network.js +0 -217
- package/dist/runner/inpage/panel-chrome.js +0 -192
- package/dist/runner/inpage/stamp.js +0 -46
- package/dist/runner/inpage/swipe-zoom.js +0 -220
- package/dist/runner/inpage/todos.js +0 -337
- package/dist/runner/interaction-patch.js +0 -384
- package/dist/runner/main.js +0 -469
- package/dist/runner/network-capture.d.ts +0 -9
- package/dist/runner/network-capture.js +0 -126
- package/dist/runner/overlay-css.d.ts +0 -3
- package/dist/runner/overlay-css.js +0 -377
- package/dist/runner/overlay-install.js +0 -90
- package/dist/runner/overlay-stage.js +0 -110
- package/dist/runner/rings.js +0 -514
- package/dist/runner/seed-mem.js +0 -110
- package/dist/runner/slides.js +0 -278
- package/dist/runner/step-mode.js +0 -703
- package/dist/runner/step-panels.js +0 -729
- package/dist/runner/teardown.js +0 -202
- package/dist/runner/todo-dock.js +0 -142
- package/dist/session/step-overlay.d.ts +0 -37
- package/dist/session/step-overlay.js +0 -244
- package/examples/routed-demo/playwright.config.ts +0 -21
- package/examples/saucedemo/src/blocks/saucedemo-web/ff-owner-auth.block.ts +0 -22
- package/templates/quickstart/src/blocks/saucedemo-web/ff-owner-auth.block.ts +0 -22
- /package/dist/{commands → cli/commands}/agent-dive-scaffold.d.ts +0 -0
- /package/dist/{commands → cli/commands}/agent-dive.d.ts +0 -0
- /package/dist/{commands → cli/commands}/extensions.d.ts +0 -0
- /package/dist/{commands → cli/commands}/init.d.ts +0 -0
- /package/dist/{commands → cli/commands}/list.d.ts +0 -0
- /package/dist/{commands → cli/commands}/map.d.ts +0 -0
- /package/dist/{commands → cli/commands}/session.d.ts +0 -0
- /package/dist/{commands → cli/commands}/test.d.ts +0 -0
- /package/dist/{commands → cli/commands}/traverse.d.ts +0 -0
- /package/dist/{commands → cli/commands}/try.d.ts +0 -0
- /package/dist/{commands → cli/commands}/upgrade.d.ts +0 -0
- /package/dist/{highlights → demo/narration}/shorthand.js +0 -0
- /package/dist/{session/overlay-beacon.d.ts → demo/overlay/beacon.d.ts} +0 -0
- /package/dist/{session/overlay-beacon.js → demo/overlay/beacon.js} +0 -0
- /package/dist/{pilot-overlay/action-ring.d.ts → demo/overlay/pilot/actions.d.ts} +0 -0
- /package/dist/{ui → demo/overlay/ui}/components/ring.d.ts +0 -0
- /package/dist/{ui → demo/overlay/ui}/stylesheet.d.ts +0 -0
- /package/dist/{ui → demo/overlay/ui}/stylesheet.js +0 -0
- /package/dist/{ui → demo/overlay/ui}/tokens.d.ts +0 -0
- /package/dist/{ui → demo/overlay/ui}/tokens.js +0 -0
- /package/dist/{highlights → demo}/types.js +0 -0
- /package/dist/{auto-session → demo}/verbose-log.d.ts +0 -0
- /package/dist/{selector.d.ts → engine/trait/selector.d.ts} +0 -0
- /package/dist/{selector.js → engine/trait/selector.js} +0 -0
- /package/dist/{trait.js → engine/trait/trait.js} +0 -0
- /package/dist/{traverse → live/traverse}/coverage.d.ts +0 -0
- /package/dist/{traverse → live/traverse}/coverage.js +0 -0
- /package/dist/{traverse → live/traverse}/lease.d.ts +0 -0
- /package/dist/{traverse → live/traverse}/lease.js +0 -0
- /package/dist/{session/block-inject.d.ts → manifest/roots.d.ts} +0 -0
- /package/dist/{blocks-select.d.ts → manifest/select.d.ts} +0 -0
- /package/dist/{blocks-select.js → manifest/select.js} +0 -0
- /package/dist/{browser.d.ts → runtime/browser.d.ts} +0 -0
- /package/dist/{env-file.d.ts → runtime/env-file.d.ts} +0 -0
- /package/dist/{playwright-config.js → runtime/playwright-config.js} +0 -0
- /package/dist/{playwright.config.d.ts → runtime/playwright.config.d.ts} +0 -0
- /package/dist/{video-dir.d.ts → runtime/video-dir.d.ts} +0 -0
- /package/dist/{webserver.d.ts → runtime/webserver.d.ts} +0 -0
package/dist/analysis/graph.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { matchBlocksSelect, } from "../blocks-select.js";
|
|
4
|
-
import { exploreRoots, injectTaggedFile } from "../session/block-inject.js";
|
|
1
|
+
import { relative } from "node:path";
|
|
2
|
+
import { scanProject } from "../manifest/project.js";
|
|
5
3
|
/**
|
|
6
4
|
* Renders a `WaygraphGraph` as Mermaid `stateDiagram-v2` text - paste
|
|
7
5
|
* straight into a `.md` file's ```mermaid fence or a live editor. `"*"`
|
|
@@ -17,127 +15,32 @@ export function toMermaid(graph) {
|
|
|
17
15
|
}
|
|
18
16
|
return lines.join("\n");
|
|
19
17
|
}
|
|
20
|
-
// ---------------------------------------------------------------------------
|
|
21
|
-
// Discovery - deliberately self-contained (no import from cli.ts): cli.ts
|
|
22
|
-
// runs its own main() unconditionally at module load, so it can't safely be
|
|
23
|
-
// imported from a test (or from here) without also running the whole CLI.
|
|
24
|
-
// These are small, stable duplicates of cli.ts's own discoverBlocks/
|
|
25
|
-
// isBlockLike/isNavBlockMarked/importModule, not a shared abstraction -
|
|
26
|
-
// simpler and lower-risk than a circular import between the two modules.
|
|
27
|
-
// ---------------------------------------------------------------------------
|
|
28
|
-
function walkDir(dir, pattern) {
|
|
29
|
-
const results = [];
|
|
30
|
-
let entries;
|
|
31
|
-
try {
|
|
32
|
-
entries = readdirSync(dir, { withFileTypes: true });
|
|
33
|
-
}
|
|
34
|
-
catch {
|
|
35
|
-
return results;
|
|
36
|
-
}
|
|
37
|
-
for (const entry of entries) {
|
|
38
|
-
const full = join(dir, entry.name);
|
|
39
|
-
if (entry.isDirectory()) {
|
|
40
|
-
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git")
|
|
41
|
-
continue;
|
|
42
|
-
results.push(...walkDir(full, pattern));
|
|
43
|
-
}
|
|
44
|
-
else if (pattern.test(entry.name)) {
|
|
45
|
-
results.push(full);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return results;
|
|
49
|
-
}
|
|
50
|
-
function discoverBlocks(projectDir) {
|
|
51
|
-
return walkDir(projectDir, /\.block\.ts$/);
|
|
52
|
-
}
|
|
53
|
-
function discoverFlows(projectDir) {
|
|
54
|
-
return walkDir(projectDir, /\.flow\.ts$/);
|
|
55
|
-
}
|
|
56
|
-
/** Block export ids a flow file uses: every identifier outside its import lines (a Block can sit in the array or in a local like `const AddShown = AddBlock.stubAfter(...)`). */
|
|
57
|
-
function extractFlowBlockRefs(flowSrc) {
|
|
58
|
-
const body = flowSrc.replace(/^\s*import[\s\S]*?;\s*$/gm, "").replace(/\/\/.*$/gm, "");
|
|
59
|
-
return body.match(/[A-Za-z_$][\w$]*/g) ?? [];
|
|
60
|
-
}
|
|
61
|
-
function exportNameToBlockName(exportName) {
|
|
62
|
-
const base = exportName.replace(/Block$/, "");
|
|
63
|
-
return base
|
|
64
|
-
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
|
|
65
|
-
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2")
|
|
66
|
-
.toLowerCase();
|
|
67
|
-
}
|
|
68
18
|
/**
|
|
69
|
-
* Blocks
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* Page hubs and Blocks listed on a Page's `methods` are not orphans.
|
|
19
|
+
* Blocks the project exports but no flow plays. Read at runtime: every flow's `blocks()` (nested flows flattened, plus
|
|
20
|
+
* the Blocks a `branch()` routes to) against every scanned Block. Page hubs and the Blocks a Page lists as its
|
|
21
|
+
* `methods` are not orphans.
|
|
73
22
|
*/
|
|
74
23
|
export async function findOrphanBlocks(projectDir) {
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
24
|
+
const scan = await scanProject(projectDir, { maps: false });
|
|
25
|
+
const used = new Set();
|
|
26
|
+
for (const { flow } of scan.flows) {
|
|
27
|
+
for (const info of flow.blocks()) {
|
|
28
|
+
used.add(info.name);
|
|
29
|
+
for (const target of Object.values(info.routes ?? {}))
|
|
30
|
+
if (target)
|
|
31
|
+
used.add(target);
|
|
81
32
|
}
|
|
82
33
|
}
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
let mod;
|
|
86
|
-
try {
|
|
87
|
-
mod = await importModule(file);
|
|
88
|
-
}
|
|
89
|
-
catch {
|
|
34
|
+
for (const b of scan.blocks) {
|
|
35
|
+
if (b.kind !== "page")
|
|
90
36
|
continue;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (!exported || typeof exported !== "object")
|
|
94
|
-
continue;
|
|
95
|
-
if (exported.__waygraphKind !== "page")
|
|
96
|
-
continue;
|
|
97
|
-
const names = exported.__waygraphMethods;
|
|
98
|
-
if (Array.isArray(names)) {
|
|
99
|
-
for (const n of names)
|
|
100
|
-
pageMethodNames.add(n);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
37
|
+
for (const name of b.block.__waygraphMethods ?? [])
|
|
38
|
+
used.add(name);
|
|
103
39
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const exportRe = /export\s+const\s+([A-Za-z_$][\w]*)\s*=/g;
|
|
109
|
-
let m;
|
|
110
|
-
while ((m = exportRe.exec(src)) !== null) {
|
|
111
|
-
const exportName = m[1];
|
|
112
|
-
if (referenced.has(exportName))
|
|
113
|
-
continue;
|
|
114
|
-
if (!/defineBlock|defineMethodBlock|defineActionBlock|definePageBlock|defineEffectBlock|defineMemEffectBlock|defineNavBlock|defineNavClickBlock|defineMemNavBlock/.test(src))
|
|
115
|
-
continue;
|
|
116
|
-
// Arrival-only Page hubs are never orphans (even if import fails without tsx).
|
|
117
|
-
const assignSlice = src.slice(m.index, m.index + exportName.length + 80);
|
|
118
|
-
if (/=\s*definePageBlock\b/.test(assignSlice))
|
|
119
|
-
continue;
|
|
120
|
-
let block = exportNameToBlockName(exportName);
|
|
121
|
-
try {
|
|
122
|
-
const mod = await importModule(file);
|
|
123
|
-
const exported = mod[exportName];
|
|
124
|
-
if (isBlockLike(exported))
|
|
125
|
-
block = exported.name;
|
|
126
|
-
if (exported &&
|
|
127
|
-
typeof exported === "object" &&
|
|
128
|
-
exported.__waygraphKind === "page") {
|
|
129
|
-
continue;
|
|
130
|
-
}
|
|
131
|
-
if (pageMethodNames.has(block))
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
catch {
|
|
135
|
-
// import may fail in partial projects - keep derived name
|
|
136
|
-
}
|
|
137
|
-
orphans.push({ exportName, block, file: relFile });
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
return orphans.sort((a, b) => a.file.localeCompare(b.file) || a.exportName.localeCompare(b.exportName));
|
|
40
|
+
return scan.blocks
|
|
41
|
+
.filter((b) => b.kind !== "page" && !used.has(b.name))
|
|
42
|
+
.map((b) => ({ exportName: b.exportName, block: b.name, file: relative(projectDir, b.absFile) }))
|
|
43
|
+
.sort((a, b) => a.file.localeCompare(b.file) || a.exportName.localeCompare(b.exportName));
|
|
141
44
|
}
|
|
142
45
|
/**
|
|
143
46
|
* Shortest Block-name path between two Checkpoint tags using `discoverGraph`
|
|
@@ -193,270 +96,44 @@ export function findBlockPathDetailed(graph, fromTag, toTag) {
|
|
|
193
96
|
return null;
|
|
194
97
|
}
|
|
195
98
|
/**
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
* `this.graph`/path-finding) and `loadBlockLibrary` (used for `this.library`/
|
|
199
|
-
* the live menu) are two independent importers, each with their own
|
|
200
|
-
* duplicate `importModule`, so each needed the same mtime-based cache-bust
|
|
201
|
-
* fix separately - fixing only one left the other still serving a session's
|
|
202
|
-
* `reloadLibrary()` a stale (or, for a brand-new file only ever discovered
|
|
203
|
-
* through THIS path, silently absent) graph.
|
|
204
|
-
*/
|
|
205
|
-
async function importModule(filePath) {
|
|
206
|
-
const resolved = resolve(filePath);
|
|
207
|
-
const url = new URL(`file://${resolved}`);
|
|
208
|
-
const mtimeMs = statSync(resolved).mtimeMs;
|
|
209
|
-
url.searchParams.set("t", String(mtimeMs));
|
|
210
|
-
return (await import(url.href));
|
|
211
|
-
}
|
|
212
|
-
function isBlockLike(val) {
|
|
213
|
-
if (val === null || typeof val !== "object")
|
|
214
|
-
return false;
|
|
215
|
-
const obj = val;
|
|
216
|
-
if (typeof obj.name !== "string")
|
|
217
|
-
return false;
|
|
218
|
-
const instruction = obj.instruction;
|
|
219
|
-
return instruction !== null && typeof instruction === "object" && typeof instruction?.act === "function";
|
|
220
|
-
}
|
|
221
|
-
/** Set by `defineNavBlock` (non-enumerable) - see src/core.ts. */
|
|
222
|
-
function isNavBlockMarked(val) {
|
|
223
|
-
const kind = val.__waygraphKind;
|
|
224
|
-
return kind === "nav" || kind === "page";
|
|
225
|
-
}
|
|
226
|
-
/** Set by `defineAssertBlock` (non-enumerable) - see src/core.ts. */
|
|
227
|
-
function isAssertBlockMarked(val) {
|
|
228
|
-
return val.__waygraphKind === "assert";
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Resolves `typeName` to every literal Checkpoint tag it can mean, within
|
|
232
|
-
* one `*.states.ts` file's own source text - `type X = Checkpoint<"Tag">`
|
|
233
|
-
* directly, or `type X = A | B | Checkpoint<"C">` (a union of other type
|
|
234
|
-
* names and/or inline Checkpoint literals) recursively. A cycle or unknown
|
|
235
|
-
* identifier just contributes no tags, rather than throwing - callers treat
|
|
236
|
-
* an empty result as "couldn't resolve," not a crash.
|
|
237
|
-
*/
|
|
238
|
-
function resolveCheckpointTags(statesSrc, typeName, seen = new Set()) {
|
|
239
|
-
if (seen.has(typeName))
|
|
240
|
-
return [];
|
|
241
|
-
seen.add(typeName);
|
|
242
|
-
const direct = new RegExp(`type\\s+${typeName}\\s*=\\s*Checkpoint<"([^"]+)">`).exec(statesSrc);
|
|
243
|
-
if (direct)
|
|
244
|
-
return [direct[1]];
|
|
245
|
-
const aliased = new RegExp(`type\\s+${typeName}\\s*=\\s*([^;]+);`).exec(statesSrc);
|
|
246
|
-
if (!aliased)
|
|
247
|
-
return [];
|
|
248
|
-
const tags = [];
|
|
249
|
-
for (const member of aliased[1].split("|").map((s) => s.trim()).filter(Boolean)) {
|
|
250
|
-
const inline = /^Checkpoint<"([^"]+)">$/.exec(member);
|
|
251
|
-
if (inline) {
|
|
252
|
-
tags.push(inline[1]);
|
|
253
|
-
}
|
|
254
|
-
else if (/^[A-Za-z_$][\w]*$/.test(member)) {
|
|
255
|
-
tags.push(...resolveCheckpointTags(statesSrc, member, seen));
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
return tags;
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Finds which file `blockFilePath`'s own `import type { ... }` statements
|
|
262
|
-
* say `typeName` comes from, resolved to a real path on disk (`.js` ->
|
|
263
|
-
* `.ts`, matching this project's own NodeNext import convention). Only
|
|
264
|
-
* follows relative imports - `typeName` imported from a package (e.g.
|
|
265
|
-
* `waygraph` itself, for `Checkpoint`) has no project file to read.
|
|
266
|
-
*/
|
|
267
|
-
function findTypeSourceFile(blockFilePath, typeName) {
|
|
268
|
-
const src = readFileSync(blockFilePath, "utf-8");
|
|
269
|
-
const importRe = /import\s+type\s*\{([^}]*)\}\s*from\s*["']([^"']+)["']/g;
|
|
270
|
-
let m;
|
|
271
|
-
while ((m = importRe.exec(src)) !== null) {
|
|
272
|
-
const names = m[1].split(",").map((s) => s.trim());
|
|
273
|
-
if (!names.includes(typeName))
|
|
274
|
-
continue;
|
|
275
|
-
const importPath = m[2];
|
|
276
|
-
if (!importPath.startsWith("."))
|
|
277
|
-
continue;
|
|
278
|
-
const resolved = join(dirname(blockFilePath), importPath.replace(/\.js$/, ".ts"));
|
|
279
|
-
if (existsSync(resolved))
|
|
280
|
-
return resolved;
|
|
281
|
-
}
|
|
282
|
-
return null;
|
|
283
|
-
}
|
|
284
|
-
/** `findTypeSourceFile` + `resolveCheckpointTags`, chained - `[]` on any failure along the way. */
|
|
285
|
-
function resolveTypeToTags(blockFilePath, typeName) {
|
|
286
|
-
const statesFile = findTypeSourceFile(blockFilePath, typeName);
|
|
287
|
-
if (!statesFile)
|
|
288
|
-
return [];
|
|
289
|
-
return resolveCheckpointTags(readFileSync(statesFile, "utf-8"), typeName);
|
|
290
|
-
}
|
|
291
|
-
/**
|
|
292
|
-
* Resolves one `defineBlock<In, Out>` generic argument, as captured by
|
|
293
|
-
* `extractDefineBlockGenerics` - either a plain type identifier (goes
|
|
294
|
-
* through `resolveTypeToTags`), an inline `Checkpoint<"Tag">` literal, or
|
|
295
|
-
* the documented wildcard forms `Checkpoint<string>`/`Checkpoint<any>` (a
|
|
296
|
-
* Block reused across several entry points, e.g. this project's own
|
|
297
|
-
* `AddToCartBlock` - reachable from anywhere, same as a NavBlock's own `"*"`).
|
|
298
|
-
*/
|
|
299
|
-
function resolveGenericArg(blockFilePath, arg) {
|
|
300
|
-
if (arg === "Checkpoint<string>" || arg === "Checkpoint<any>")
|
|
301
|
-
return ["*"];
|
|
302
|
-
const inline = /^Checkpoint<"([^"]+)">$/.exec(arg);
|
|
303
|
-
if (inline)
|
|
304
|
-
return [inline[1]];
|
|
305
|
-
return resolveTypeToTags(blockFilePath, arg);
|
|
306
|
-
}
|
|
307
|
-
/** Every `defineBlock` / `defineEffectBlock` / `defineMemEffectBlock` `<In, Out>` call site. */
|
|
308
|
-
function extractDefineBlockGenerics(src) {
|
|
309
|
-
// Each argument is either a plain identifier or an inline `Checkpoint<...>`
|
|
310
|
-
// (its own angle brackets, so the outer defineX<...> pair alone won't
|
|
311
|
-
// balance correctly against a naive greedy match) - captured as a single
|
|
312
|
-
// alternation so both shapes come out of the same two capture groups.
|
|
313
|
-
// Effect helpers are TypeScript salt over defineBlock - same In/Out edges.
|
|
314
|
-
const arg = String.raw `(Checkpoint<[^>]*>|[A-Za-z_$][\w]*)`;
|
|
315
|
-
const re = new RegExp(String.raw `define(?:(?:Mem)?Effect|Method|Action)?Block<\s*${arg}\s*,\s*${arg}\s*>`, "g");
|
|
316
|
-
// Matches: defineBlock | defineMethodBlock | defineActionBlock | defineEffectBlock |
|
|
317
|
-
// defineMemEffectBlock (Nav / NavClick / Page use runtime markers, not this regex.)
|
|
318
|
-
const calls = [];
|
|
319
|
-
let m;
|
|
320
|
-
while ((m = re.exec(src)) !== null) {
|
|
321
|
-
calls.push({ in: m[1], out: m[2] });
|
|
322
|
-
}
|
|
323
|
-
return calls;
|
|
324
|
-
}
|
|
325
|
-
/**
|
|
326
|
-
* Walks every `*.block.ts` file under `projectDir` and builds the app's own
|
|
327
|
-
* state graph. Shares the same in-process-import limitation `waygraph
|
|
328
|
-
* check` already has: a target project whose own `waygraph`/`playwright`
|
|
329
|
-
* are genuinely separate installs (not symlinked into this same
|
|
330
|
-
* node_modules resolution) can crash Playwright's own "second copy" guard
|
|
331
|
-
* on import - acceptable for an introspection command the same way it
|
|
332
|
-
* already is for `check`, unlike `chain`, which spawns a child process
|
|
333
|
-
* specifically because it also EXECUTES Blocks, not just imports them.
|
|
99
|
+
* The project's state graph: Checkpoints are nodes, Blocks are edges. Built from the manifest scan, which reads each Block's
|
|
100
|
+
* route at runtime.
|
|
334
101
|
*/
|
|
335
102
|
export async function discoverGraph(projectDir, opts) {
|
|
336
|
-
const
|
|
103
|
+
const scan = await scanProject(projectDir, { blocksSelect: opts?.blocksSelect, inject: opts?.inject, flows: false });
|
|
104
|
+
return graphFromScan(scan);
|
|
105
|
+
}
|
|
106
|
+
/** The graph of an existing scan. */
|
|
107
|
+
export function graphFromScan(scan) {
|
|
337
108
|
const nodeTags = new Set();
|
|
338
109
|
const edges = [];
|
|
339
|
-
const
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
//
|
|
344
|
-
if (
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
110
|
+
const seen = new Set();
|
|
111
|
+
for (const b of scan.blocks) {
|
|
112
|
+
if (b.to.length === 0)
|
|
113
|
+
continue;
|
|
114
|
+
// Arrival-only Page hubs register the Checkpoint but are not a way to get there; a deep-linking Page is.
|
|
115
|
+
if (b.kind === "page" && b.block.__waygraphPageDeepLink !== true) {
|
|
116
|
+
for (const to of b.to)
|
|
117
|
+
nodeTags.add(to);
|
|
118
|
+
continue;
|
|
348
119
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
// Dual @playwright/test installs fail here - surface instead of empty graph.
|
|
358
|
-
if (/second time|playwright/i.test(msg)) {
|
|
359
|
-
console.error(`waygraph graph: skip ${relFile}: ${msg.split("\n")[0]}`);
|
|
360
|
-
}
|
|
361
|
-
continue;
|
|
362
|
-
}
|
|
363
|
-
const src = readFileSync(file, "utf-8");
|
|
364
|
-
// Assumes source order matches export-object iteration order - true for
|
|
365
|
-
// this codebase's own convention of one Block per file; a file with
|
|
366
|
-
// several regular Blocks in an unusual order is a known edge case, not
|
|
367
|
-
// handled specially here.
|
|
368
|
-
const calls = extractDefineBlockGenerics(src);
|
|
369
|
-
let callIndex = 0;
|
|
370
|
-
for (const exported of Object.values(mod)) {
|
|
371
|
-
if (!isBlockLike(exported))
|
|
372
|
-
continue;
|
|
373
|
-
const blockName = exported.name;
|
|
374
|
-
if (select &&
|
|
375
|
-
!matchBlocksSelect(select, {
|
|
376
|
-
relFile: relFile.replace(/\\/g, "/"),
|
|
377
|
-
blockName,
|
|
378
|
-
})) {
|
|
379
|
-
continue;
|
|
380
|
-
}
|
|
381
|
-
if (isAssertBlockMarked(exported)) {
|
|
382
|
-
try {
|
|
383
|
-
// Same input-independent resolve() shape Nav/Page Blocks already
|
|
384
|
-
// get this shortcut for - defineAssertBlock's own resolve() is
|
|
385
|
-
// always `() => checkpoint(options.checkpoint)`, so no <In, Out>
|
|
386
|
-
// generic needs to appear in source text for this to be found.
|
|
387
|
-
const resolveFn = exported.instruction.resolve;
|
|
388
|
-
const resolved = await resolveFn(undefined);
|
|
389
|
-
const to = resolved.__state;
|
|
390
|
-
nodeTags.add(to);
|
|
391
|
-
// Self-loop by construction (defineAssertBlock is self-loop-only).
|
|
392
|
-
edges.push({ block: blockName, file: relFile, from: to, to, kind: "action" });
|
|
393
|
-
}
|
|
394
|
-
catch {
|
|
395
|
-
skipped.push({ block: blockName, file: relFile, reason: "assertBlock resolve() threw" });
|
|
396
|
-
}
|
|
397
|
-
continue;
|
|
398
|
-
}
|
|
399
|
-
if (isNavBlockMarked(exported)) {
|
|
400
|
-
try {
|
|
401
|
-
// NavBlock / PageBlock resolve() ignores input - always checkpoint(tag).
|
|
402
|
-
const resolveFn = exported.instruction.resolve;
|
|
403
|
-
const resolved = await resolveFn(undefined);
|
|
404
|
-
const to = resolved.__state;
|
|
405
|
-
nodeTags.add(to);
|
|
406
|
-
// Arrival-only Page hubs register the Checkpoint node but do not emit
|
|
407
|
-
// a Start-here edge (no deep link). Methods own the action edges.
|
|
408
|
-
const isPage = exported.__waygraphKind === "page";
|
|
409
|
-
const deepLink = !isPage ||
|
|
410
|
-
exported.__waygraphPageDeepLink === true;
|
|
411
|
-
if (deepLink) {
|
|
412
|
-
// `from: [...]` on the Nav = only those Checkpoints; otherwise reachable from anywhere.
|
|
413
|
-
const navFrom = exported.__waygraphNavFrom;
|
|
414
|
-
for (const from of navFrom ?? ["*"]) {
|
|
415
|
-
if (from !== "*")
|
|
416
|
-
nodeTags.add(from);
|
|
417
|
-
edges.push({ block: blockName, file: relFile, from, to, kind: "nav" });
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
catch {
|
|
422
|
-
skipped.push({ block: blockName, file: relFile, reason: "NavBlock/PageBlock resolve() threw" });
|
|
423
|
-
}
|
|
424
|
-
continue;
|
|
425
|
-
}
|
|
426
|
-
const call = calls[callIndex++];
|
|
427
|
-
if (!call) {
|
|
428
|
-
skipped.push({
|
|
429
|
-
block: blockName,
|
|
430
|
-
file: relFile,
|
|
431
|
-
reason: "no defineBlock/defineMethodBlock/defineEffectBlock<In, Out> generic call found",
|
|
432
|
-
});
|
|
433
|
-
continue;
|
|
434
|
-
}
|
|
435
|
-
const fromTags = resolveGenericArg(file, call.in);
|
|
436
|
-
const toTags = resolveGenericArg(file, call.out);
|
|
437
|
-
if (fromTags.length === 0 || toTags.length === 0) {
|
|
438
|
-
const badName = fromTags.length === 0 ? call.in : call.out;
|
|
439
|
-
skipped.push({ block: blockName, file: relFile, reason: `couldn't resolve "${badName}" to a Checkpoint tag` });
|
|
120
|
+
const kind = b.kind === "nav" || b.kind === "page" ? "nav" : "action";
|
|
121
|
+
for (const from of b.from) {
|
|
122
|
+
for (const to of b.to) {
|
|
123
|
+
if (from !== "*")
|
|
124
|
+
nodeTags.add(from);
|
|
125
|
+
nodeTags.add(to);
|
|
126
|
+
const key = `${b.name}\0${from}\0${to}`;
|
|
127
|
+
if (seen.has(key))
|
|
440
128
|
continue;
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
for (const to of toTags) {
|
|
444
|
-
if (from !== "*")
|
|
445
|
-
nodeTags.add(from);
|
|
446
|
-
nodeTags.add(to);
|
|
447
|
-
const key = `${blockName}\0${from}\0${to}`;
|
|
448
|
-
if (edgeSeen.has(key))
|
|
449
|
-
continue;
|
|
450
|
-
edgeSeen.add(key);
|
|
451
|
-
edges.push({ block: blockName, file: relFile, from, to, kind: "action" });
|
|
452
|
-
}
|
|
453
|
-
}
|
|
129
|
+
seen.add(key);
|
|
130
|
+
edges.push({ block: b.name, file: b.file, from, to, kind });
|
|
454
131
|
}
|
|
455
132
|
}
|
|
456
133
|
}
|
|
457
134
|
return {
|
|
458
135
|
nodes: [...nodeTags].sort().map((checkpoint) => ({ checkpoint })),
|
|
459
136
|
edges,
|
|
460
|
-
skipped,
|
|
137
|
+
skipped: scan.skipped,
|
|
461
138
|
};
|
|
462
139
|
}
|
|
@@ -13,46 +13,11 @@
|
|
|
13
13
|
* Self-contained (no import from cli.ts), same reasoning as graph.ts's own
|
|
14
14
|
* header comment: cli.ts runs main() unconditionally at module load.
|
|
15
15
|
*/
|
|
16
|
-
import { existsSync
|
|
16
|
+
import { existsSync } from "node:fs";
|
|
17
17
|
import { join, dirname, relative, sep } from "node:path";
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
let entries;
|
|
22
|
-
try {
|
|
23
|
-
entries = readdirSync(dir, { withFileTypes: true });
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
return results;
|
|
27
|
-
}
|
|
28
|
-
for (const entry of entries) {
|
|
29
|
-
const full = join(dir, entry.name);
|
|
30
|
-
if (entry.isDirectory()) {
|
|
31
|
-
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git")
|
|
32
|
-
continue;
|
|
33
|
-
results.push(...walkBlockFiles(full));
|
|
34
|
-
}
|
|
35
|
-
else if (/\.block\.ts$/.test(entry.name)) {
|
|
36
|
-
results.push(full);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return results;
|
|
40
|
-
}
|
|
41
|
-
function isBlockLike(val) {
|
|
42
|
-
if (val === null || typeof val !== "object")
|
|
43
|
-
return false;
|
|
44
|
-
const obj = val;
|
|
45
|
-
if (typeof obj.name !== "string")
|
|
46
|
-
return false;
|
|
47
|
-
const instruction = obj.instruction;
|
|
48
|
-
return instruction !== null && typeof instruction === "object" && typeof instruction?.act === "function";
|
|
49
|
-
}
|
|
50
|
-
async function importModule(filePath) {
|
|
51
|
-
const url = pathToFileURL(filePath);
|
|
52
|
-
const mtimeMs = statSync(filePath).mtimeMs;
|
|
53
|
-
url.searchParams.set("t", String(mtimeMs));
|
|
54
|
-
return (await import(url.href));
|
|
55
|
-
}
|
|
18
|
+
import { importFresh, isBlockLike, walkDir } from "../manifest/scan.js";
|
|
19
|
+
const walkBlockFiles = (dir) => walkDir(dir, /\.block\.ts$/);
|
|
20
|
+
const importModule = importFresh;
|
|
56
21
|
/**
|
|
57
22
|
* `(group)` segments never appear in the real URL (Next.js route-group
|
|
58
23
|
* convention this whole system is explicitly modeled on) - excluded from
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type PracticeKind = "
|
|
1
|
+
export type PracticeKind = "multi-input" | "combined-action" | "empty-verify" | "overcomplex-selector" | "inline-selector-should-use-sel-file";
|
|
2
2
|
export interface PracticeWarning {
|
|
3
3
|
kind: PracticeKind;
|
|
4
4
|
file: string;
|
|
@@ -5,31 +5,29 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { readFileSync, readdirSync } from "node:fs";
|
|
7
7
|
import { dirname, relative } from "node:path";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* A wildcard Out (the Block's result is untyped). A wildcard In is fine - it's the documented
|
|
12
|
-
* "reachable from anywhere" form (graph.ts treats it like a NavBlock's "*").
|
|
13
|
-
*/
|
|
14
|
-
function hasWildcardOut(src) {
|
|
15
|
-
for (const m of src.matchAll(BLOCK_GENERICS)) {
|
|
16
|
-
const out = (m[2] ?? m[1]).trim();
|
|
17
|
-
if (/^Checkpoint\s*<\s*string\s*>$/.test(out))
|
|
18
|
-
return true;
|
|
19
|
-
}
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
/** defineAssertBlock({ … }) with no explicit Out type — defaults to wildcard. */
|
|
23
|
-
const ASSERT_NO_TYPE_ARG = /\bdefineAssertBlock\s*\(\s*\{/;
|
|
8
|
+
import { Node, SyntaxKind } from "ts-morph";
|
|
9
|
+
import { parseSource } from "../manifest/source.js";
|
|
24
10
|
/** defineAssertBlock, any form - used to scope the empty-verify check below. */
|
|
25
11
|
const IS_ASSERT_BLOCK = /\bdefineAssertBlock\s*[<(]/;
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
12
|
+
/** A Method/Effect's route as written (`from: LoginPage, to: LoggedIn`), from the AST - a transition when they differ. */
|
|
13
|
+
function routeAsWritten(file) {
|
|
14
|
+
const sf = parseSource(file);
|
|
15
|
+
for (const call of sf.getDescendantsOfKind(SyntaxKind.CallExpression)) {
|
|
16
|
+
if (!/^define(Method|Effect)Block$/.test(call.getExpression().getText()))
|
|
17
|
+
continue;
|
|
18
|
+
const options = call.getArguments()[0];
|
|
19
|
+
if (!Node.isObjectLiteralExpression(options))
|
|
20
|
+
continue;
|
|
21
|
+
const text = (name) => {
|
|
22
|
+
const prop = options.getProperty(name);
|
|
23
|
+
return Node.isPropertyAssignment(prop) ? prop.getInitializerOrThrow().getText() : undefined;
|
|
24
|
+
};
|
|
25
|
+
const to = text("to");
|
|
26
|
+
if (to)
|
|
27
|
+
return { from: text("from") ?? "*", to };
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
33
31
|
/** `verify: []` - a literal empty array, the codegen-stub shape this check exists for. */
|
|
34
32
|
const EMPTY_VERIFY_ARRAY = /\bverify\s*:\s*\[\s*\]/;
|
|
35
33
|
/** Any `verify:` key at all, empty or not. */
|
|
@@ -86,21 +84,6 @@ export function collectPracticeWarnings(projectDir, walkDir, opts) {
|
|
|
86
84
|
const rel = relative(projectDir, file).replace(/\\/g, "/");
|
|
87
85
|
const src = readFileSync(file, "utf-8");
|
|
88
86
|
const ignore = ignoredKindsForFile(src);
|
|
89
|
-
if (!isIgnored("wildcard-checkpoint", ignore) && hasWildcardOut(src)) {
|
|
90
|
-
warnings.push({
|
|
91
|
-
kind: "wildcard-checkpoint",
|
|
92
|
-
file: rel,
|
|
93
|
-
detail: "the Block's output is Checkpoint<string>, so its result is untyped — use a typed Checkpoint from " +
|
|
94
|
-
"src/states/ (e.g. defineMethodBlock<LoginPage, LoggedIn>); a wildcard input is fine",
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
if (!isIgnored("assert-no-type-arg", ignore) && ASSERT_NO_TYPE_ARG.test(src)) {
|
|
98
|
-
warnings.push({
|
|
99
|
-
kind: "assert-no-type-arg",
|
|
100
|
-
file: rel,
|
|
101
|
-
detail: "defineAssertBlock({…}) without an explicit type argument — add defineAssertBlock<YourCheckpoint>({…}) so defineFlow typing stays honest",
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
87
|
const isMethodOrEffect = METHOD_OR_EFFECT_FILE.test(rel) || METHOD_OR_EFFECT_DEFINE.test(src);
|
|
105
88
|
if (isMethodOrEffect) {
|
|
106
89
|
const fills = countMatches(src, /\.fill\s*\(/g);
|
|
@@ -119,15 +102,15 @@ export function collectPracticeWarnings(projectDir, walkDir, opts) {
|
|
|
119
102
|
detail: "Method/Effect act() mixes .fill() and .click() — fill and submit must be separate Blocks (see examples/saucedemo login split)",
|
|
120
103
|
});
|
|
121
104
|
}
|
|
122
|
-
const
|
|
123
|
-
const isTransition = !!
|
|
105
|
+
const route = routeAsWritten(file);
|
|
106
|
+
const isTransition = !!route && route.from !== route.to;
|
|
124
107
|
if (isTransition &&
|
|
125
108
|
!isIgnored("empty-verify", ignore) &&
|
|
126
109
|
(!HAS_VERIFY_KEY.test(src) || EMPTY_VERIFY_ARRAY.test(src))) {
|
|
127
110
|
warnings.push({
|
|
128
111
|
kind: "empty-verify",
|
|
129
112
|
file: rel,
|
|
130
|
-
detail: `transition Block (${
|
|
113
|
+
detail: `transition Block (${route.from} → ${route.to}) has no verify checks — resolve() moving ` +
|
|
131
114
|
"to a new Checkpoint is never confirmed by anything; add a Trait (or defineAssertBlock right after it), " +
|
|
132
115
|
"or opt out explicitly with // waygraph-ignore: empty-verify if that's intentional",
|
|
133
116
|
});
|
|
@@ -173,10 +156,6 @@ export function collectPracticeWarnings(projectDir, walkDir, opts) {
|
|
|
173
156
|
}
|
|
174
157
|
export function practiceKindLabel(kind) {
|
|
175
158
|
switch (kind) {
|
|
176
|
-
case "wildcard-checkpoint":
|
|
177
|
-
return "wildcard Checkpoint<string>";
|
|
178
|
-
case "assert-no-type-arg":
|
|
179
|
-
return "assert block missing type arg";
|
|
180
159
|
case "multi-input":
|
|
181
160
|
return "multiple inputs in one Block";
|
|
182
161
|
case "combined-action":
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
export interface OptionSpec {
|
|
3
|
+
type: "boolean" | "string";
|
|
4
|
+
multiple?: boolean;
|
|
5
|
+
/** How the value reads in the help: `<url>`, `N`. */
|
|
6
|
+
value?: string;
|
|
7
|
+
help: string;
|
|
8
|
+
}
|
|
9
|
+
export type OptionTable = Readonly<Record<string, OptionSpec>>;
|
|
10
|
+
/** What a table parses to: a boolean, a string, or (multiple) a list, per flag; absent when not given. */
|
|
11
|
+
export type ParsedOptions<T extends OptionTable> = {
|
|
12
|
+
[K in keyof T]?: T[K]["type"] extends "boolean" ? boolean : T[K] extends {
|
|
13
|
+
multiple: true;
|
|
14
|
+
} ? string[] : string;
|
|
15
|
+
};
|
|
16
|
+
export interface ParsedCommand<T extends OptionTable> {
|
|
17
|
+
values: ParsedOptions<T>;
|
|
18
|
+
positionals: string[];
|
|
19
|
+
tokens: ReturnType<typeof parseArgs>["tokens"] & {};
|
|
20
|
+
}
|
|
21
|
+
export declare function parseCommand<T extends OptionTable>(command: string, table: T, argv: string[]): ParsedCommand<T>;
|
|
22
|
+
/** The table as aligned help lines (`--name <value> help`). */
|
|
23
|
+
export declare function helpLines(table: OptionTable, indent?: number): string;
|