command-stream 0.8.2 → 0.9.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/js/examples/01-basic-streaming.mjs +14 -0
- package/js/examples/02-async-iterator.mjs +9 -0
- package/js/examples/03-file-and-console.mjs +16 -0
- package/js/examples/04-claude-jq-pipe.mjs +16 -0
- package/js/examples/CI-DEBUG-README.md +138 -0
- package/js/examples/README-examples.mjs +111 -0
- package/js/examples/README.md +345 -0
- package/js/examples/STREAMING_INTERFACES_SUMMARY.md +116 -0
- package/js/examples/add-test-timeouts.js +107 -0
- package/js/examples/ansi-default-preserved.mjs +11 -0
- package/js/examples/ansi-global-config.mjs +12 -0
- package/js/examples/ansi-reset-default.mjs +12 -0
- package/js/examples/ansi-strip-utils.mjs +12 -0
- package/js/examples/baseline-child-process.mjs +23 -0
- package/js/examples/baseline-claude-test.mjs +47 -0
- package/js/examples/baseline-working.mjs +34 -0
- package/js/examples/capture-mirror-comparison.mjs +23 -0
- package/js/examples/capture-mirror-default.mjs +11 -0
- package/js/examples/capture-mirror-performance.mjs +16 -0
- package/js/examples/capture-mirror-show-only.mjs +16 -0
- package/js/examples/capture-mirror-silent-processing.mjs +16 -0
- package/js/examples/ci-debug-baseline-vs-library.mjs +265 -0
- package/js/examples/ci-debug-es-module-loading.mjs +184 -0
- package/js/examples/ci-debug-signal-handling.mjs +225 -0
- package/js/examples/ci-debug-stdout-buffering.mjs +94 -0
- package/js/examples/ci-debug-test-timeouts.mjs +259 -0
- package/js/examples/claude-exact-file-output.mjs +20 -0
- package/js/examples/claude-exact-jq.mjs +13 -0
- package/js/examples/claude-exact-streaming.mjs +13 -0
- package/js/examples/claude-jq-pipeline.mjs +13 -0
- package/js/examples/claude-json-stream.mjs +39 -0
- package/js/examples/claude-streaming-basic.mjs +99 -0
- package/js/examples/claude-streaming-demo.mjs +126 -0
- package/js/examples/claude-streaming-final.mjs +20 -0
- package/js/examples/cleanup-verification-test.mjs +115 -0
- package/js/examples/colors-buffer-processing.mjs +14 -0
- package/js/examples/colors-default-preserved.mjs +15 -0
- package/js/examples/colors-per-command-config.mjs +15 -0
- package/js/examples/colors-strip-ansi.mjs +13 -0
- package/js/examples/commandstream-jq.mjs +29 -0
- package/js/examples/commandstream-working.mjs +23 -0
- package/js/examples/comprehensive-streams-demo.mjs +121 -0
- package/js/examples/ctrl-c-concurrent-processes.mjs +20 -0
- package/js/examples/ctrl-c-long-running-command.mjs +20 -0
- package/js/examples/ctrl-c-real-system-command.mjs +17 -0
- package/js/examples/ctrl-c-sleep-command.mjs +17 -0
- package/js/examples/ctrl-c-stdin-forwarding.mjs +20 -0
- package/js/examples/ctrl-c-virtual-command.mjs +17 -0
- package/js/examples/debug-already-started.mjs +20 -0
- package/js/examples/debug-ansi-processing.mjs +42 -0
- package/js/examples/debug-basic-streaming.mjs +44 -0
- package/js/examples/debug-buildshellcommand.mjs +82 -0
- package/js/examples/debug-child-process.mjs +43 -0
- package/js/examples/debug-child-state.mjs +55 -0
- package/js/examples/debug-chunking.mjs +38 -0
- package/js/examples/debug-command-parsing.mjs +61 -0
- package/js/examples/debug-complete-consolidation.mjs +97 -0
- package/js/examples/debug-echo-args.mjs +22 -0
- package/js/examples/debug-emit-timing.mjs +28 -0
- package/js/examples/debug-end-event.mjs +56 -0
- package/js/examples/debug-errexit.mjs +16 -0
- package/js/examples/debug-event-emission.mjs +40 -0
- package/js/examples/debug-event-timing.mjs +67 -0
- package/js/examples/debug-event-vs-result.mjs +30 -0
- package/js/examples/debug-exact-command.mjs +28 -0
- package/js/examples/debug-exact-test-scenario.mjs +44 -0
- package/js/examples/debug-execution-path.mjs +27 -0
- package/js/examples/debug-exit-command.mjs +38 -0
- package/js/examples/debug-exit-virtual.mjs +54 -0
- package/js/examples/debug-finish-consolidation.mjs +44 -0
- package/js/examples/debug-force-cleanup.mjs +47 -0
- package/js/examples/debug-getter-basic.mjs +13 -0
- package/js/examples/debug-getter-direct.mjs +23 -0
- package/js/examples/debug-getter-internals.mjs +61 -0
- package/js/examples/debug-handler-detection.mjs +65 -0
- package/js/examples/debug-idempotent-finish.mjs +54 -0
- package/js/examples/debug-idempotent-kill.mjs +58 -0
- package/js/examples/debug-interpolation-individual.mjs +88 -0
- package/js/examples/debug-interpolation-issue.mjs +101 -0
- package/js/examples/debug-jq-streaming.mjs +57 -0
- package/js/examples/debug-jq-tty-colors.mjs +168 -0
- package/js/examples/debug-kill-cleanup.mjs +56 -0
- package/js/examples/debug-kill-method.mjs +33 -0
- package/js/examples/debug-listener-interference.mjs +38 -0
- package/js/examples/debug-listener-lifecycle.mjs +50 -0
- package/js/examples/debug-listener-timing.mjs +62 -0
- package/js/examples/debug-listeners-property.mjs +34 -0
- package/js/examples/debug-map-methods.mjs +39 -0
- package/js/examples/debug-not-awaited-cleanup.mjs +106 -0
- package/js/examples/debug-off-method.mjs +28 -0
- package/js/examples/debug-option-merging.mjs +17 -0
- package/js/examples/debug-options.mjs +36 -0
- package/js/examples/debug-output.mjs +25 -0
- package/js/examples/debug-pattern-matching.mjs +69 -0
- package/js/examples/debug-pipeline-cat.mjs +28 -0
- package/js/examples/debug-pipeline-cleanup.mjs +71 -0
- package/js/examples/debug-pipeline-error-detailed.mjs +78 -0
- package/js/examples/debug-pipeline-error.mjs +65 -0
- package/js/examples/debug-pipeline-issue.mjs +26 -0
- package/js/examples/debug-pipeline-method.mjs +22 -0
- package/js/examples/debug-pipeline-stream.mjs +66 -0
- package/js/examples/debug-pipeline.mjs +14 -0
- package/js/examples/debug-process-exit-trace.mjs +41 -0
- package/js/examples/debug-process-path.mjs +38 -0
- package/js/examples/debug-property-check.mjs +29 -0
- package/js/examples/debug-resource-cleanup.mjs +83 -0
- package/js/examples/debug-shell-args.mjs +103 -0
- package/js/examples/debug-sigint-child-handler.mjs +44 -0
- package/js/examples/debug-sigint-forwarding.mjs +61 -0
- package/js/examples/debug-sigint-handler-install.mjs +79 -0
- package/js/examples/debug-sigint-handler-order.mjs +85 -0
- package/js/examples/debug-sigint-listeners.mjs +48 -0
- package/js/examples/debug-sigint-start-pattern.mjs +62 -0
- package/js/examples/debug-sigint-timer.mjs +40 -0
- package/js/examples/debug-simple-command.mjs +49 -0
- package/js/examples/debug-simple-getter.mjs +30 -0
- package/js/examples/debug-simple.mjs +39 -0
- package/js/examples/debug-simplified-finished.mjs +102 -0
- package/js/examples/debug-stack-overflow.mjs +25 -0
- package/js/examples/debug-stdin-simple.mjs +28 -0
- package/js/examples/debug-stdin.mjs +28 -0
- package/js/examples/debug-stream-emitter-isolated.mjs +45 -0
- package/js/examples/debug-stream-emitter.mjs +25 -0
- package/js/examples/debug-stream-events.mjs +70 -0
- package/js/examples/debug-stream-generator.mjs +23 -0
- package/js/examples/debug-stream-getter-issue.mjs +37 -0
- package/js/examples/debug-stream-getter.mjs +19 -0
- package/js/examples/debug-stream-internals.mjs +64 -0
- package/js/examples/debug-stream-method.mjs +46 -0
- package/js/examples/debug-stream-object.mjs +58 -0
- package/js/examples/debug-stream-properties.mjs +37 -0
- package/js/examples/debug-stream-timing.mjs +28 -0
- package/js/examples/debug-streaming.mjs +24 -0
- package/js/examples/debug-test-isolation.mjs +54 -0
- package/js/examples/debug-test-state.mjs +27 -0
- package/js/examples/debug-user-sigint.mjs +19 -0
- package/js/examples/debug-virtual-disable.mjs +21 -0
- package/js/examples/debug-virtual-vs-real.mjs +68 -0
- package/js/examples/debug-with-trace.mjs +23 -0
- package/js/examples/debug_parent_stream.mjs +22 -0
- package/js/examples/emulate-claude-stream.mjs +30 -0
- package/js/examples/emulated-streaming-direct.mjs +22 -0
- package/js/examples/emulated-streaming-jq-pipe.mjs +22 -0
- package/js/examples/emulated-streaming-sh-pipe.mjs +23 -0
- package/js/examples/events-build-process.mjs +73 -0
- package/js/examples/events-concurrent-streams.mjs +51 -0
- package/js/examples/events-error-handling.mjs +59 -0
- package/js/examples/events-file-monitoring.mjs +66 -0
- package/js/examples/events-interactive-simulation.mjs +69 -0
- package/js/examples/events-log-processing.mjs +72 -0
- package/js/examples/events-network-monitoring.mjs +68 -0
- package/js/examples/events-ping-basic.mjs +37 -0
- package/js/examples/events-progress-tracking.mjs +55 -0
- package/js/examples/events-stdin-input.mjs +34 -0
- package/js/examples/example-ansi-ls.mjs +39 -0
- package/js/examples/example-top.mjs +27 -0
- package/js/examples/final-ping-stdin-proof.mjs +88 -0
- package/js/examples/final-test-shell-operators.mjs +123 -0
- package/js/examples/final-working-examples.mjs +162 -0
- package/js/examples/gh-auth-test.mjs +103 -0
- package/js/examples/gh-delete-hang-test.mjs +79 -0
- package/js/examples/gh-gist-creation-test.mjs +276 -0
- package/js/examples/gh-gist-minimal-test.mjs +89 -0
- package/js/examples/gh-hang-exact-original.mjs +83 -0
- package/js/examples/gh-hang-reproduction.mjs +151 -0
- package/js/examples/gh-hang-test-with-redirect.mjs +45 -0
- package/js/examples/gh-hang-test-without-redirect.mjs +43 -0
- package/js/examples/gh-minimal-hang-check.mjs +33 -0
- package/js/examples/gh-operations-with-cd.mjs +187 -0
- package/js/examples/gh-output-test.mjs +102 -0
- package/js/examples/gh-reproduce-hang.mjs +41 -0
- package/js/examples/git-operations-with-cd.mjs +186 -0
- package/js/examples/interactive-math-calc.mjs +45 -0
- package/js/examples/interactive-top-fixed.mjs +25 -0
- package/js/examples/interactive-top-improved.mjs +72 -0
- package/js/examples/interactive-top-pty-logging.mjs +69 -0
- package/js/examples/interactive-top-pty.mjs +27 -0
- package/js/examples/interactive-top-with-logging.mjs +56 -0
- package/js/examples/interactive-top.mjs +29 -0
- package/js/examples/jq-color-demo.mjs +53 -0
- package/js/examples/jq-colors-streaming.mjs +42 -0
- package/js/examples/manual-ctrl-c-test.mjs +50 -0
- package/js/examples/methods-multiple-options.mjs +25 -0
- package/js/examples/methods-run-basic.mjs +10 -0
- package/js/examples/methods-start-basic.mjs +10 -0
- package/js/examples/node-compat-data-events.mjs +36 -0
- package/js/examples/node-compat-readable-event.mjs +29 -0
- package/js/examples/node-compat-small-buffer.mjs +33 -0
- package/js/examples/options-capture-false.mjs +12 -0
- package/js/examples/options-combined-settings.mjs +13 -0
- package/js/examples/options-custom-input.mjs +16 -0
- package/js/examples/options-default-behavior.mjs +10 -0
- package/js/examples/options-maximum-performance.mjs +15 -0
- package/js/examples/options-mirror-false.mjs +10 -0
- package/js/examples/options-performance-mode.mjs +13 -0
- package/js/examples/options-performance-optimization.mjs +14 -0
- package/js/examples/options-run-alias-demo.mjs +15 -0
- package/js/examples/options-run-alias.mjs +10 -0
- package/js/examples/options-silent-execution.mjs +14 -0
- package/js/examples/options-streaming-capture.mjs +24 -0
- package/js/examples/options-streaming-multiple.mjs +35 -0
- package/js/examples/options-streaming-silent.mjs +21 -0
- package/js/examples/options-streaming-stdin.mjs +21 -0
- package/js/examples/ping-streaming-filtered.mjs +22 -0
- package/js/examples/ping-streaming-interruptible.mjs +47 -0
- package/js/examples/ping-streaming-silent.mjs +24 -0
- package/js/examples/ping-streaming-simple.mjs +13 -0
- package/js/examples/ping-streaming-statistics.mjs +49 -0
- package/js/examples/ping-streaming-timestamps.mjs +22 -0
- package/js/examples/ping-streaming.mjs +48 -0
- package/js/examples/prove-ping-stdin-limitation.mjs +94 -0
- package/js/examples/readme-example.mjs +39 -0
- package/js/examples/realtime-json-stream.mjs +143 -0
- package/js/examples/reliable-stdin-commands.mjs +135 -0
- package/js/examples/reproduce-issue-135-v2.mjs +15 -0
- package/js/examples/reproduce-issue-135.mjs +17 -0
- package/js/examples/shell-cd-behavior.mjs +88 -0
- package/js/examples/sigint-forwarding-test.mjs +60 -0
- package/js/examples/sigint-handler-test.mjs +72 -0
- package/js/examples/simple-async-test.mjs +49 -0
- package/js/examples/simple-claude-test.mjs +17 -0
- package/js/examples/simple-event-test.mjs +33 -0
- package/js/examples/simple-jq-streaming.mjs +48 -0
- package/js/examples/simple-stream-demo.mjs +35 -0
- package/js/examples/simple-test-sleep.js +30 -0
- package/js/examples/simple-working-stdin.mjs +30 -0
- package/js/examples/streaming-behavior-test.mjs +116 -0
- package/js/examples/streaming-direct-command.mjs +21 -0
- package/js/examples/streaming-filtered-output.mjs +33 -0
- package/js/examples/streaming-grep-pipeline.mjs +21 -0
- package/js/examples/streaming-interactive-stdin.mjs +24 -0
- package/js/examples/streaming-jq-pipeline.mjs +23 -0
- package/js/examples/streaming-multistage-pipeline.mjs +23 -0
- package/js/examples/streaming-pipes-event-pattern.mjs +27 -0
- package/js/examples/streaming-pipes-multistage.mjs +22 -0
- package/js/examples/streaming-pipes-realtime-jq.mjs +23 -0
- package/js/examples/streaming-progress-tracking.mjs +34 -0
- package/js/examples/streaming-reusable-configs.mjs +52 -0
- package/js/examples/streaming-silent-capture.mjs +20 -0
- package/js/examples/streaming-test-simple.mjs +70 -0
- package/js/examples/streaming-virtual-pipeline.mjs +18 -0
- package/js/examples/syntax-basic-comparison.mjs +31 -0
- package/js/examples/syntax-basic-options.mjs +12 -0
- package/js/examples/syntax-combined-options.mjs +19 -0
- package/js/examples/syntax-command-chaining.mjs +12 -0
- package/js/examples/syntax-custom-directory.mjs +10 -0
- package/js/examples/syntax-custom-environment.mjs +13 -0
- package/js/examples/syntax-custom-stdin.mjs +10 -0
- package/js/examples/syntax-mixed-regular.mjs +11 -0
- package/js/examples/syntax-mixed-usage.mjs +15 -0
- package/js/examples/syntax-multiple-listeners.mjs +87 -0
- package/js/examples/syntax-piping-comparison.mjs +32 -0
- package/js/examples/syntax-reusable-config.mjs +16 -0
- package/js/examples/syntax-reusable-configs.mjs +21 -0
- package/js/examples/syntax-silent-operations.mjs +10 -0
- package/js/examples/syntax-stdin-option.mjs +12 -0
- package/js/examples/temp-sigint-test.mjs +21 -0
- package/js/examples/test-actual-buildshell.mjs +44 -0
- package/js/examples/test-async-streams-working.mjs +102 -0
- package/js/examples/test-async-streams.mjs +90 -0
- package/js/examples/test-auth-parse.mjs +74 -0
- package/js/examples/test-auto-quoting.mjs +57 -0
- package/js/examples/test-auto-start-fix.mjs +95 -0
- package/js/examples/test-baseline-sigint.mjs +38 -0
- package/js/examples/test-buffer-behavior.mjs +39 -0
- package/js/examples/test-buffers-simple.mjs +35 -0
- package/js/examples/test-bun-specific-issue.mjs +106 -0
- package/js/examples/test-bun-streaming.mjs +81 -0
- package/js/examples/test-cat-direct.mjs +41 -0
- package/js/examples/test-cat-pipe.mjs +34 -0
- package/js/examples/test-cd-behavior.mjs +42 -0
- package/js/examples/test-child-process-timing.mjs +53 -0
- package/js/examples/test-child-sigint-handler.mjs +62 -0
- package/js/examples/test-cleanup-simple.mjs +21 -0
- package/js/examples/test-comprehensive-tracing.mjs +58 -0
- package/js/examples/test-correct-space-handling.mjs +46 -0
- package/js/examples/test-ctrl-c-debug.mjs +44 -0
- package/js/examples/test-ctrl-c-inherit.mjs +30 -0
- package/js/examples/test-ctrl-c-sleep.mjs +31 -0
- package/js/examples/test-ctrl-c.mjs +17 -0
- package/js/examples/test-debug-new-options.mjs +55 -0
- package/js/examples/test-debug-pty.mjs +49 -0
- package/js/examples/test-debug-tee.mjs +38 -0
- package/js/examples/test-debug.mjs +25 -0
- package/js/examples/test-direct-jq.mjs +47 -0
- package/js/examples/test-direct-pipe-reading.mjs +119 -0
- package/js/examples/test-direct-pipe.sh +28 -0
- package/js/examples/test-double-quoting-prevention.mjs +138 -0
- package/js/examples/test-edge-cases-quoting.mjs +89 -0
- package/js/examples/test-events.mjs +37 -0
- package/js/examples/test-explicit-stdio.mjs +51 -0
- package/js/examples/test-final-streaming.mjs +71 -0
- package/js/examples/test-fix.mjs +71 -0
- package/js/examples/test-incremental-streaming.mjs +46 -0
- package/js/examples/test-individual-spawn.mjs +35 -0
- package/js/examples/test-inherit-stdout-not-stdin.mjs +133 -0
- package/js/examples/test-injection-protection.mjs +77 -0
- package/js/examples/test-interactive-streaming.mjs +140 -0
- package/js/examples/test-interactive-top.md +24 -0
- package/js/examples/test-interactive.mjs +17 -0
- package/js/examples/test-interpolation.mjs +14 -0
- package/js/examples/test-interrupt.mjs +40 -0
- package/js/examples/test-issue-135-comprehensive.mjs +41 -0
- package/js/examples/test-issue12-detailed.mjs +89 -0
- package/js/examples/test-issue12-exact.mjs +33 -0
- package/js/examples/test-jq-color.mjs +57 -0
- package/js/examples/test-jq-colors.mjs +41 -0
- package/js/examples/test-jq-compact.mjs +33 -0
- package/js/examples/test-jq-native.sh +10 -0
- package/js/examples/test-jq-pipeline-behavior.mjs +80 -0
- package/js/examples/test-jq-realtime.mjs +40 -0
- package/js/examples/test-manual-start.mjs +54 -0
- package/js/examples/test-mixed-quoting.mjs +88 -0
- package/js/examples/test-multi-stream.mjs +50 -0
- package/js/examples/test-multistage-debug.mjs +44 -0
- package/js/examples/test-native-spawn-vs-command-stream.mjs +154 -0
- package/js/examples/test-no-parse-pipeline.mjs +33 -0
- package/js/examples/test-non-virtual.mjs +52 -0
- package/js/examples/test-operators.mjs +53 -0
- package/js/examples/test-parent-continues.mjs +44 -0
- package/js/examples/test-path-interpolation.mjs +86 -0
- package/js/examples/test-ping-kill-and-stdin.mjs +98 -0
- package/js/examples/test-ping.mjs +12 -0
- package/js/examples/test-pty-spawn.mjs +101 -0
- package/js/examples/test-pty.mjs +38 -0
- package/js/examples/test-quote-behavior-summary.mjs +110 -0
- package/js/examples/test-quote-edge-cases.mjs +69 -0
- package/js/examples/test-quote-parsing.mjs +23 -0
- package/js/examples/test-raw-function.mjs +153 -0
- package/js/examples/test-raw-streaming.mjs +47 -0
- package/js/examples/test-readme-examples.mjs +142 -0
- package/js/examples/test-real-cat.mjs +28 -0
- package/js/examples/test-real-commands.mjs +21 -0
- package/js/examples/test-real-shell.mjs +31 -0
- package/js/examples/test-real-stdin-commands.mjs +160 -0
- package/js/examples/test-runner-batched.mjs +98 -0
- package/js/examples/test-runner-simple.mjs +80 -0
- package/js/examples/test-runner.mjs +67 -0
- package/js/examples/test-scope-parse.mjs +31 -0
- package/js/examples/test-sh-pipeline.mjs +24 -0
- package/js/examples/test-shell-detection.mjs +71 -0
- package/js/examples/test-shell-parser.mjs +37 -0
- package/js/examples/test-sigint-behavior.mjs +241 -0
- package/js/examples/test-sigint-handling.sh +14 -0
- package/js/examples/test-simple-pipe.mjs +12 -0
- package/js/examples/test-simple-streaming.mjs +32 -0
- package/js/examples/test-sleep-stdin.js +27 -0
- package/js/examples/test-sleep.mjs +56 -0
- package/js/examples/test-smart-quoting.mjs +180 -0
- package/js/examples/test-spaces-in-path.mjs +48 -0
- package/js/examples/test-special-chars-quoting.mjs +54 -0
- package/js/examples/test-stdin-after-start.mjs +39 -0
- package/js/examples/test-stdin-simple.mjs +67 -0
- package/js/examples/test-stdin-timing.mjs +74 -0
- package/js/examples/test-stdio-combinations.mjs +124 -0
- package/js/examples/test-stream-access.mjs +84 -0
- package/js/examples/test-stream-cleanup.mjs +27 -0
- package/js/examples/test-stream-readers.mjs +152 -0
- package/js/examples/test-streaming-final.mjs +57 -0
- package/js/examples/test-streaming-interfaces.mjs +141 -0
- package/js/examples/test-streaming-timing.mjs +27 -0
- package/js/examples/test-streaming.mjs +32 -0
- package/js/examples/test-streams-stdin-comprehensive.mjs +134 -0
- package/js/examples/test-streams-stdin-ctrl-c.mjs +96 -0
- package/js/examples/test-template-literal.mjs +26 -0
- package/js/examples/test-template-vs-interpolation.mjs +49 -0
- package/js/examples/test-timing.mjs +41 -0
- package/js/examples/test-top-inherit-stdout-stdin-control.mjs +123 -0
- package/js/examples/test-top-quit-stdin.mjs +118 -0
- package/js/examples/test-trace-option.mjs +21 -0
- package/js/examples/test-user-double-quotes.mjs +36 -0
- package/js/examples/test-user-single-quotes.mjs +36 -0
- package/js/examples/test-verbose.mjs +18 -0
- package/js/examples/test-verbose2.mjs +32 -0
- package/js/examples/test-virtual-streaming.mjs +125 -0
- package/js/examples/test-waiting-command.mjs +52 -0
- package/js/examples/test-waiting-commands.mjs +83 -0
- package/js/examples/test-watch-mode.mjs +104 -0
- package/js/examples/test-yes-cancellation.mjs +26 -0
- package/js/examples/test-yes-detailed.mjs +58 -0
- package/js/examples/test-yes-trace.mjs +28 -0
- package/js/examples/trace-abort-controller.mjs +30 -0
- package/js/examples/trace-error-handling.mjs +22 -0
- package/js/examples/trace-pipeline-command.mjs +22 -0
- package/js/examples/trace-signal-handling.mjs +35 -0
- package/js/examples/trace-simple-command.mjs +18 -0
- package/js/examples/trace-stderr-output.mjs +22 -0
- package/js/examples/verify-fix-both-runtimes.mjs +73 -0
- package/js/examples/verify-issue12-fixed.mjs +78 -0
- package/js/examples/which-command-common-commands.mjs +19 -0
- package/js/examples/which-command-gh-test.mjs +23 -0
- package/js/examples/which-command-nonexistent.mjs +20 -0
- package/js/examples/which-command-system-comparison.mjs +28 -0
- package/js/examples/working-example.mjs +13 -0
- package/js/examples/working-stdin-examples.mjs +138 -0
- package/js/examples/working-streaming-demo.mjs +49 -0
- package/{src → js/src}/$.mjs +20 -4
- package/{src → js/src}/$.utils.mjs +14 -2
- package/js/tests/$.features.test.mjs +283 -0
- package/js/tests/$.test.mjs +935 -0
- package/js/tests/builtin-commands.test.mjs +387 -0
- package/js/tests/bun-shell-path-fix.test.mjs +115 -0
- package/js/tests/bun.features.test.mjs +189 -0
- package/js/tests/cd-virtual-command.test.mjs +622 -0
- package/js/tests/cleanup-verification.test.mjs +127 -0
- package/js/tests/ctrl-c-baseline.test.mjs +207 -0
- package/js/tests/ctrl-c-basic.test.mjs +220 -0
- package/js/tests/ctrl-c-library.test.mjs +197 -0
- package/js/tests/ctrl-c-signal.test.mjs +915 -0
- package/js/tests/examples.test.mjs +252 -0
- package/js/tests/execa.features.test.mjs +198 -0
- package/js/tests/gh-commands.test.mjs +164 -0
- package/js/tests/gh-gist-operations.test.mjs +221 -0
- package/js/tests/git-gh-cd.test.mjs +466 -0
- package/js/tests/interactive-option.test.mjs +114 -0
- package/js/tests/interactive-streaming.test.mjs +307 -0
- package/js/tests/issue-135-final.test.mjs +58 -0
- package/js/tests/jq-color-behavior.test.mjs +140 -0
- package/js/tests/jq.test.mjs +318 -0
- package/js/tests/options-examples.test.mjs +106 -0
- package/js/tests/options-syntax.test.mjs +112 -0
- package/js/tests/path-interpolation.test.mjs +412 -0
- package/js/tests/pipe.test.mjs +291 -0
- package/js/tests/raw-function.test.mjs +266 -0
- package/js/tests/readme-examples.test.mjs +427 -0
- package/js/tests/resource-cleanup-internals.test.mjs +669 -0
- package/js/tests/shell-settings.test.mjs +279 -0
- package/js/tests/sigint-cleanup-isolated.test.mjs +151 -0
- package/js/tests/sigint-cleanup.test.mjs +118 -0
- package/js/tests/start-run-edge-cases.test.mjs +152 -0
- package/js/tests/start-run-options.test.mjs +181 -0
- package/js/tests/stderr-output-handling.test.mjs +279 -0
- package/js/tests/streaming-interfaces.test.mjs +194 -0
- package/js/tests/sync.test.mjs +297 -0
- package/js/tests/system-pipe.test.mjs +226 -0
- package/js/tests/test-cleanup.mjs +200 -0
- package/js/tests/test-helper-fixed.mjs +148 -0
- package/js/tests/test-helper-v2.mjs +118 -0
- package/js/tests/test-helper.mjs +171 -0
- package/js/tests/test-sigint-child.js +15 -0
- package/js/tests/text-method.test.mjs +225 -0
- package/js/tests/virtual.test.mjs +364 -0
- package/js/tests/yes-command-cleanup.test.mjs +208 -0
- package/js/tests/zx.features.test.mjs +233 -0
- package/package.json +13 -12
- package/rust/Cargo.lock +947 -0
- package/rust/Cargo.toml +47 -0
- package/rust/src/commands/basename.rs +69 -0
- package/rust/src/commands/cat.rs +123 -0
- package/rust/src/commands/cd.rs +67 -0
- package/rust/src/commands/cp.rs +187 -0
- package/rust/src/commands/dirname.rs +57 -0
- package/rust/src/commands/echo.rs +73 -0
- package/rust/src/commands/env.rs +33 -0
- package/rust/src/commands/exit.rs +36 -0
- package/rust/src/commands/false.rs +24 -0
- package/rust/src/commands/ls.rs +182 -0
- package/rust/src/commands/mkdir.rs +98 -0
- package/rust/src/commands/mod.rs +200 -0
- package/rust/src/commands/mv.rs +180 -0
- package/rust/src/commands/pwd.rs +28 -0
- package/rust/src/commands/rm.rs +150 -0
- package/rust/src/commands/seq.rs +179 -0
- package/rust/src/commands/sleep.rs +97 -0
- package/rust/src/commands/test.rs +204 -0
- package/rust/src/commands/touch.rs +99 -0
- package/rust/src/commands/true.rs +24 -0
- package/rust/src/commands/which.rs +87 -0
- package/rust/src/commands/yes.rs +99 -0
- package/rust/src/lib.rs +492 -0
- package/rust/src/main.rs +37 -0
- package/rust/src/shell_parser.rs +565 -0
- package/rust/src/utils.rs +335 -0
- package/rust/tests/builtin_commands.rs +549 -0
- package/rust/tests/process_runner.rs +286 -0
- package/rust/tests/shell_parser.rs +296 -0
- package/rust/tests/utils.rs +282 -0
- package/rust/tests/virtual_commands.rs +199 -0
- /package/{src → js/src}/commands/$.basename.mjs +0 -0
- /package/{src → js/src}/commands/$.cat.mjs +0 -0
- /package/{src → js/src}/commands/$.cd.mjs +0 -0
- /package/{src → js/src}/commands/$.cp.mjs +0 -0
- /package/{src → js/src}/commands/$.dirname.mjs +0 -0
- /package/{src → js/src}/commands/$.echo.mjs +0 -0
- /package/{src → js/src}/commands/$.env.mjs +0 -0
- /package/{src → js/src}/commands/$.exit.mjs +0 -0
- /package/{src → js/src}/commands/$.false.mjs +0 -0
- /package/{src → js/src}/commands/$.ls.mjs +0 -0
- /package/{src → js/src}/commands/$.mkdir.mjs +0 -0
- /package/{src → js/src}/commands/$.mv.mjs +0 -0
- /package/{src → js/src}/commands/$.pwd.mjs +0 -0
- /package/{src → js/src}/commands/$.rm.mjs +0 -0
- /package/{src → js/src}/commands/$.seq.mjs +0 -0
- /package/{src → js/src}/commands/$.sleep.mjs +0 -0
- /package/{src → js/src}/commands/$.test.mjs +0 -0
- /package/{src → js/src}/commands/$.touch.mjs +0 -0
- /package/{src → js/src}/commands/$.true.mjs +0 -0
- /package/{src → js/src}/commands/$.which.mjs +0 -0
- /package/{src → js/src}/commands/$.yes.mjs +0 -0
- /package/{src → js/src}/shell-parser.mjs +0 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { describe, test, expect } from 'bun:test';
|
|
2
|
+
import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup
|
|
3
|
+
import { $, disableVirtualCommands } from '../src/$.mjs';
|
|
4
|
+
|
|
5
|
+
// Disable virtual commands to ensure we're testing system/built-in commands
|
|
6
|
+
disableVirtualCommands();
|
|
7
|
+
|
|
8
|
+
describe('.text() method for Bun.$ compatibility', () => {
|
|
9
|
+
test('sync execution should have .text() method', () => {
|
|
10
|
+
const result = $`echo "sync test"`.sync();
|
|
11
|
+
|
|
12
|
+
expect(typeof result.text).toBe('function');
|
|
13
|
+
expect(result.text).toBeInstanceOf(Function);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('async execution should have .text() method', async () => {
|
|
17
|
+
const result = await $`echo "async test"`;
|
|
18
|
+
|
|
19
|
+
expect(typeof result.text).toBe('function');
|
|
20
|
+
expect(result.text).toBeInstanceOf(Function);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('.text() should return stdout content (sync)', async () => {
|
|
24
|
+
const result = $`echo "hello world"`.sync();
|
|
25
|
+
const text = await result.text();
|
|
26
|
+
|
|
27
|
+
expect(text).toBe('hello world\n');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('.text() should return stdout content (async)', async () => {
|
|
31
|
+
const result = await $`echo "hello async"`;
|
|
32
|
+
const text = await result.text();
|
|
33
|
+
|
|
34
|
+
expect(text).toBe('hello async\n');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('.text() should handle empty output', async () => {
|
|
38
|
+
// Use a command that produces no output
|
|
39
|
+
const result = await $`true`;
|
|
40
|
+
const text = await result.text();
|
|
41
|
+
|
|
42
|
+
expect(text).toBe('');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('.text() should handle multiline output', async () => {
|
|
46
|
+
// Use seq to generate multiline output
|
|
47
|
+
const result = await $`seq 1 3`;
|
|
48
|
+
const text = await result.text();
|
|
49
|
+
|
|
50
|
+
expect(text).toBe('1\n2\n3\n');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('.text() should work with built-in commands', async () => {
|
|
54
|
+
const result = await $`seq 1 3`;
|
|
55
|
+
const text = await result.text();
|
|
56
|
+
|
|
57
|
+
expect(text).toBe('1\n2\n3\n');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('.text() should work with cat built-in command', async () => {
|
|
61
|
+
// Create a test file first
|
|
62
|
+
await $`echo "test content" > temp-text-test.txt`;
|
|
63
|
+
|
|
64
|
+
const result = await $`cat temp-text-test.txt`;
|
|
65
|
+
const text = await result.text();
|
|
66
|
+
|
|
67
|
+
expect(text).toBe('test content\n');
|
|
68
|
+
|
|
69
|
+
// Clean up
|
|
70
|
+
await $`rm temp-text-test.txt`;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('.text() should work with ls built-in command', async () => {
|
|
74
|
+
const result = await $`ls -1 js/tests/`;
|
|
75
|
+
const text = await result.text();
|
|
76
|
+
|
|
77
|
+
// Should contain at least this test file
|
|
78
|
+
expect(text).toContain('text-method.test.mjs');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('.text() should work with pwd built-in command', async () => {
|
|
82
|
+
const result = await $`pwd`;
|
|
83
|
+
const text = await result.text();
|
|
84
|
+
|
|
85
|
+
// Should return a path ending with newline
|
|
86
|
+
expect(text.trim()).toBeTruthy();
|
|
87
|
+
expect(text.endsWith('\n')).toBe(true);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('.text() should return empty string for commands with no stdout', async () => {
|
|
91
|
+
const result =
|
|
92
|
+
await $`mkdir -p temp-dir-for-text-test && rmdir temp-dir-for-text-test`;
|
|
93
|
+
const text = await result.text();
|
|
94
|
+
|
|
95
|
+
expect(text).toBe('');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test('.text() should work with piped commands (when supported)', async () => {
|
|
99
|
+
// Note: Pipeline with built-ins currently treats them as system commands
|
|
100
|
+
// This test checks the behavior - expecting an error about unsupported pipeline
|
|
101
|
+
try {
|
|
102
|
+
const result = await $`seq 1 3 | cat`;
|
|
103
|
+
// If this succeeds somehow, check the .text() method exists
|
|
104
|
+
if (result.text) {
|
|
105
|
+
const text = await result.text();
|
|
106
|
+
expect(typeof text).toBe('string');
|
|
107
|
+
}
|
|
108
|
+
} catch (error) {
|
|
109
|
+
// Expected for now - pipeline with system commands not supported
|
|
110
|
+
expect(error.message).toContain('not yet supported');
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test('.text() should work with complex pipeline (when supported)', async () => {
|
|
115
|
+
// Create a temp file for sorting
|
|
116
|
+
await $`echo "3" > temp-sort-test.txt`;
|
|
117
|
+
await $`echo "1" >> temp-sort-test.txt`;
|
|
118
|
+
await $`echo "2" >> temp-sort-test.txt`;
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
const result = await $`cat temp-sort-test.txt | sort`;
|
|
122
|
+
// If this succeeds somehow, check the .text() method exists
|
|
123
|
+
if (result.text) {
|
|
124
|
+
const text = await result.text();
|
|
125
|
+
expect(typeof text).toBe('string');
|
|
126
|
+
}
|
|
127
|
+
} catch (error) {
|
|
128
|
+
// Expected for now - pipeline with system commands not supported
|
|
129
|
+
expect(error.message).toContain('not yet supported');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Clean up
|
|
133
|
+
await $`rm temp-sort-test.txt`;
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test('.text() should handle commands with stderr but no stdout', async () => {
|
|
137
|
+
try {
|
|
138
|
+
const result = await $`cat nonexistent-file-text-test.txt`;
|
|
139
|
+
const text = await result.text();
|
|
140
|
+
|
|
141
|
+
expect(text).toBe('');
|
|
142
|
+
} catch (error) {
|
|
143
|
+
// Some shells might throw on error, that's fine
|
|
144
|
+
expect(error.result).toBeDefined();
|
|
145
|
+
if (error.result) {
|
|
146
|
+
const text = await error.result.text();
|
|
147
|
+
expect(text).toBe('');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test('.text() should be consistent with .stdout property', async () => {
|
|
153
|
+
const result = await $`echo "consistency test"`;
|
|
154
|
+
const text = await result.text();
|
|
155
|
+
|
|
156
|
+
expect(text).toBe(result.stdout);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test('.text() can be called multiple times', async () => {
|
|
160
|
+
const result = await $`echo "multiple calls"`;
|
|
161
|
+
|
|
162
|
+
const text1 = await result.text();
|
|
163
|
+
const text2 = await result.text();
|
|
164
|
+
const text3 = await result.text();
|
|
165
|
+
|
|
166
|
+
expect(text1).toBe('multiple calls\n');
|
|
167
|
+
expect(text2).toBe('multiple calls\n');
|
|
168
|
+
expect(text3).toBe('multiple calls\n');
|
|
169
|
+
expect(text1).toBe(text2);
|
|
170
|
+
expect(text2).toBe(text3);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test('.text() returns a Promise', () => {
|
|
174
|
+
const result = $`echo "promise test"`.sync();
|
|
175
|
+
const textPromise = result.text();
|
|
176
|
+
|
|
177
|
+
expect(textPromise).toBeInstanceOf(Promise);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test('.text() should work with binary-safe content', async () => {
|
|
181
|
+
const testContent = 'content with special chars: üñíçødé 🚀';
|
|
182
|
+
// Write content directly without shell quoting issues
|
|
183
|
+
await $`touch temp-unicode-test.txt`;
|
|
184
|
+
await $`echo ${testContent} > temp-unicode-test.txt`;
|
|
185
|
+
|
|
186
|
+
const result = await $`cat temp-unicode-test.txt`;
|
|
187
|
+
const text = await result.text();
|
|
188
|
+
|
|
189
|
+
expect(text).toContain('üñíçødé');
|
|
190
|
+
expect(text).toContain('🚀');
|
|
191
|
+
|
|
192
|
+
// Clean up
|
|
193
|
+
await $`rm temp-unicode-test.txt`;
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test('.text() should work with .pipe() method results', async () => {
|
|
197
|
+
const result = await $`echo "pipe test"`.pipe($`cat`);
|
|
198
|
+
const text = await result.text();
|
|
199
|
+
|
|
200
|
+
expect(text).toBe('pipe test\n');
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test('.text() method should be accessible', () => {
|
|
204
|
+
const result = $`echo "test"`.sync();
|
|
205
|
+
const keys = Object.keys(result);
|
|
206
|
+
|
|
207
|
+
// .text() method should be accessible
|
|
208
|
+
expect(result.text).toBeDefined();
|
|
209
|
+
expect(typeof result.text).toBe('function');
|
|
210
|
+
|
|
211
|
+
// Check if it's in the keys (implementation detail)
|
|
212
|
+
const hasTextKey = keys.includes('text');
|
|
213
|
+
expect(typeof hasTextKey).toBe('boolean'); // Just verify it's a boolean
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test('.text() should handle very large output efficiently', async () => {
|
|
217
|
+
// Generate a reasonably large output
|
|
218
|
+
const result = await $`seq 1 1000`;
|
|
219
|
+
const text = await result.text();
|
|
220
|
+
|
|
221
|
+
expect(text).toContain('1\n');
|
|
222
|
+
expect(text).toContain('1000\n');
|
|
223
|
+
expect(text.split('\n')).toHaveLength(1001); // 1000 numbers + empty line at end
|
|
224
|
+
});
|
|
225
|
+
});
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { test, expect, describe, beforeEach, afterEach } from 'bun:test';
|
|
2
|
+
import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs';
|
|
3
|
+
import { isWindows } from './test-helper.mjs';
|
|
4
|
+
import {
|
|
5
|
+
$,
|
|
6
|
+
shell,
|
|
7
|
+
register,
|
|
8
|
+
unregister,
|
|
9
|
+
listCommands,
|
|
10
|
+
enableVirtualCommands,
|
|
11
|
+
} from '../src/$.mjs';
|
|
12
|
+
|
|
13
|
+
// Helper function to setup shell settings
|
|
14
|
+
function setupShellSettings() {
|
|
15
|
+
shell.errexit(false);
|
|
16
|
+
shell.verbose(false);
|
|
17
|
+
shell.xtrace(false);
|
|
18
|
+
shell.pipefail(false);
|
|
19
|
+
shell.nounset(false);
|
|
20
|
+
enableVirtualCommands();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe('Virtual Commands System', () => {
|
|
24
|
+
beforeEach(async () => {
|
|
25
|
+
await beforeTestCleanup();
|
|
26
|
+
setupShellSettings();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
afterEach(async () => {
|
|
30
|
+
await afterTestCleanup();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('Registration API', () => {
|
|
34
|
+
test('should register and execute custom virtual command', async () => {
|
|
35
|
+
register('greet', async ({ args }) => {
|
|
36
|
+
const name = args[0] || 'World';
|
|
37
|
+
return { stdout: `Hello, ${name}!\n`, code: 0 };
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const result = await $`greet Alice`;
|
|
41
|
+
|
|
42
|
+
expect(result.stdout).toBe('Hello, Alice!\n');
|
|
43
|
+
expect(result.code).toBe(0);
|
|
44
|
+
|
|
45
|
+
// Cleanup
|
|
46
|
+
unregister('greet');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('should unregister commands', async () => {
|
|
50
|
+
register('temp', async () => ({ stdout: 'temp', code: 0 }));
|
|
51
|
+
|
|
52
|
+
// Verify it exists
|
|
53
|
+
expect(listCommands()).toContain('temp');
|
|
54
|
+
|
|
55
|
+
// Unregister
|
|
56
|
+
const removed = unregister('temp');
|
|
57
|
+
expect(removed).toBe(true);
|
|
58
|
+
expect(listCommands()).not.toContain('temp');
|
|
59
|
+
|
|
60
|
+
// Verify it falls back to system command
|
|
61
|
+
try {
|
|
62
|
+
await $`temp`; // Should fail since 'temp' is not a system command
|
|
63
|
+
} catch (error) {
|
|
64
|
+
expect(error.code).not.toBe(0);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('should list registered commands', () => {
|
|
69
|
+
const initialCommands = listCommands();
|
|
70
|
+
|
|
71
|
+
register('test1', async () => ({ stdout: '', code: 0 }));
|
|
72
|
+
register('test2', async () => ({ stdout: '', code: 0 }));
|
|
73
|
+
|
|
74
|
+
const commands = listCommands();
|
|
75
|
+
expect(commands).toContain('test1');
|
|
76
|
+
expect(commands).toContain('test2');
|
|
77
|
+
expect(commands.length).toBe(initialCommands.length + 2);
|
|
78
|
+
|
|
79
|
+
// Cleanup
|
|
80
|
+
unregister('test1');
|
|
81
|
+
unregister('test2');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('Built-in Commands', () => {
|
|
86
|
+
// Skip on Windows - uses Unix path /tmp
|
|
87
|
+
test.skipIf(isWindows)('should execute virtual cd command', async () => {
|
|
88
|
+
const originalCwd = process.cwd();
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
const result = await $`cd /tmp`;
|
|
92
|
+
expect(result.code).toBe(0);
|
|
93
|
+
expect(process.cwd()).not.toBe(originalCwd);
|
|
94
|
+
expect(process.cwd()).toMatch(/tmp/);
|
|
95
|
+
} finally {
|
|
96
|
+
process.chdir(originalCwd);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('should execute virtual pwd command', async () => {
|
|
101
|
+
const result = await $`pwd`;
|
|
102
|
+
expect(result.code).toBe(0);
|
|
103
|
+
expect(result.stdout.trim()).toBe(process.cwd());
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('should execute virtual echo command', async () => {
|
|
107
|
+
const result = await $`echo Hello World`;
|
|
108
|
+
expect(result.code).toBe(0);
|
|
109
|
+
expect(result.stdout).toBe('Hello World\n');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('should execute echo with -n flag', async () => {
|
|
113
|
+
const result = await $`echo -n Hello`;
|
|
114
|
+
expect(result.code).toBe(0);
|
|
115
|
+
expect(result.stdout).toBe('Hello');
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('should execute virtual sleep command', async () => {
|
|
119
|
+
const start = Date.now();
|
|
120
|
+
const result = await $`sleep 0.1`;
|
|
121
|
+
const elapsed = Date.now() - start;
|
|
122
|
+
|
|
123
|
+
expect(result.code).toBe(0);
|
|
124
|
+
expect(elapsed).toBeGreaterThan(90); // At least 90ms
|
|
125
|
+
expect(elapsed).toBeLessThan(200); // But not too long
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('should execute virtual true command', async () => {
|
|
129
|
+
const result = await $`true`;
|
|
130
|
+
expect(result.code).toBe(0);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test('should execute virtual false command', async () => {
|
|
134
|
+
const result = await $`false`;
|
|
135
|
+
expect(result.code).toBe(1);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test('should execute virtual which command', async () => {
|
|
139
|
+
const result = await $`which echo`;
|
|
140
|
+
expect(result.code).toBe(0);
|
|
141
|
+
expect(result.stdout).toBe('echo: shell builtin\n');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('should execute virtual exit command', async () => {
|
|
145
|
+
const result = await $`exit 0`;
|
|
146
|
+
expect(result.code).toBe(0);
|
|
147
|
+
|
|
148
|
+
const result2 = await $`exit 42`;
|
|
149
|
+
expect(result2.code).toBe(42);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test('should execute virtual env command', async () => {
|
|
153
|
+
const result = await $`env`;
|
|
154
|
+
expect(result.code).toBe(0);
|
|
155
|
+
expect(result.stdout).toContain('PATH=');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test('should execute virtual test command', async () => {
|
|
159
|
+
// Test directory
|
|
160
|
+
const result1 = await $`test -d .`;
|
|
161
|
+
expect(result1.code).toBe(0);
|
|
162
|
+
|
|
163
|
+
// Test file
|
|
164
|
+
const result2 = await $`test -f package.json`;
|
|
165
|
+
expect(result2.code).toBe(0);
|
|
166
|
+
|
|
167
|
+
// Test non-existent
|
|
168
|
+
const result3 = await $`test -f nonexistent-file-99999`;
|
|
169
|
+
expect(result3.code).toBe(1);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe('Virtual vs System Commands', () => {
|
|
174
|
+
test('should prioritize virtual commands over system commands', async () => {
|
|
175
|
+
// Register a virtual 'ls' that overrides system ls
|
|
176
|
+
register('ls', async ({ args }) => ({
|
|
177
|
+
stdout: 'virtual ls output\n',
|
|
178
|
+
code: 0,
|
|
179
|
+
}));
|
|
180
|
+
|
|
181
|
+
const result = await $`ls`;
|
|
182
|
+
expect(result.stdout).toBe('virtual ls output\n');
|
|
183
|
+
|
|
184
|
+
// Cleanup - should fall back to system ls
|
|
185
|
+
unregister('ls');
|
|
186
|
+
|
|
187
|
+
const systemResult = await $`ls`;
|
|
188
|
+
expect(systemResult.stdout).not.toBe('virtual ls output\n');
|
|
189
|
+
expect(systemResult.code).toBe(0); // System ls should work
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test('should fall back to system commands when virtual not found', async () => {
|
|
193
|
+
// This should use system echo (since we didn't override it... wait, we did!)
|
|
194
|
+
// Let's test with a command we definitely didn't override
|
|
195
|
+
const result = await $`date`;
|
|
196
|
+
expect(result.code).toBe(0);
|
|
197
|
+
expect(result.stdout).toContain('202'); // Should contain year
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
describe('Streaming Virtual Commands', () => {
|
|
202
|
+
test('should support async generator virtual commands', async () => {
|
|
203
|
+
register('count', async function* ({ args }) {
|
|
204
|
+
const max = parseInt(args[0] || 3);
|
|
205
|
+
for (let i = 1; i <= max; i++) {
|
|
206
|
+
yield `${i}\n`;
|
|
207
|
+
// Small delay to test streaming
|
|
208
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
const chunks = [];
|
|
213
|
+
const cmd = $`count 3`;
|
|
214
|
+
for await (const chunk of cmd.stream()) {
|
|
215
|
+
chunks.push(chunk.data.toString());
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
expect(chunks.length).toBeGreaterThan(0);
|
|
219
|
+
const output = chunks.join('');
|
|
220
|
+
|
|
221
|
+
// Check if we got the numbers in order, regardless of newlines
|
|
222
|
+
expect(output).toContain('1');
|
|
223
|
+
expect(output).toContain('2');
|
|
224
|
+
expect(output).toContain('3');
|
|
225
|
+
|
|
226
|
+
// The output should be either "1\n2\n3\n" or "123" depending on buffering
|
|
227
|
+
const normalized = output.replace(/\n/g, '');
|
|
228
|
+
expect(normalized).toBe('123');
|
|
229
|
+
|
|
230
|
+
// Cleanup
|
|
231
|
+
unregister('count');
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test('should handle events with streaming virtual commands', async () => {
|
|
235
|
+
register('stream-test', async function* ({ args }) {
|
|
236
|
+
yield 'chunk1\n';
|
|
237
|
+
yield 'chunk2\n';
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
const events = [];
|
|
241
|
+
const result = await new Promise((resolve) => {
|
|
242
|
+
const cmd = $`stream-test`;
|
|
243
|
+
cmd.on('stdout', () => events.push('stdout'));
|
|
244
|
+
cmd.on('data', (chunk) => events.push(`data-${chunk.type}`));
|
|
245
|
+
cmd.on('end', resolve);
|
|
246
|
+
cmd.then().catch(() => {}); // Start execution
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
expect(events.length).toBeGreaterThan(0);
|
|
250
|
+
expect(events).toContain('stdout');
|
|
251
|
+
expect(events).toContain('data-stdout');
|
|
252
|
+
|
|
253
|
+
// Cleanup
|
|
254
|
+
unregister('stream-test');
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
describe('Error Handling', () => {
|
|
259
|
+
test('should handle virtual command errors', async () => {
|
|
260
|
+
register('fail', async ({ args }) => {
|
|
261
|
+
throw new Error('Virtual command failed');
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
const result = await $`fail`;
|
|
265
|
+
expect(result.code).toBe(1);
|
|
266
|
+
expect(result.stderr).toContain('Virtual command failed');
|
|
267
|
+
|
|
268
|
+
// Cleanup
|
|
269
|
+
unregister('fail');
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
test('should respect errexit setting with virtual commands', async () => {
|
|
273
|
+
register('fail-code', async ({ args }) => ({
|
|
274
|
+
stdout: '',
|
|
275
|
+
stderr: 'Failed',
|
|
276
|
+
code: 42,
|
|
277
|
+
}));
|
|
278
|
+
|
|
279
|
+
shell.errexit(true);
|
|
280
|
+
|
|
281
|
+
try {
|
|
282
|
+
await $`fail-code`;
|
|
283
|
+
expect(true).toBe(false); // Should not reach here
|
|
284
|
+
} catch (error) {
|
|
285
|
+
expect(error.code).toBe(42);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
shell.errexit(false);
|
|
289
|
+
const result = await $`fail-code`;
|
|
290
|
+
expect(result.code).toBe(42);
|
|
291
|
+
|
|
292
|
+
// Cleanup
|
|
293
|
+
unregister('fail-code');
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
describe('Command Arguments and Stdin', () => {
|
|
298
|
+
test('should pass arguments correctly to virtual commands', async () => {
|
|
299
|
+
register('args-test', async ({ args }) => ({
|
|
300
|
+
stdout: `Args: [${args.join(', ')}]\n`,
|
|
301
|
+
code: 0,
|
|
302
|
+
}));
|
|
303
|
+
|
|
304
|
+
const result = await $`args-test one "two three" four`;
|
|
305
|
+
expect(result.stdout).toBe('Args: [one, two three, four]\n');
|
|
306
|
+
|
|
307
|
+
// Cleanup
|
|
308
|
+
unregister('args-test');
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
test('should pass stdin to virtual commands', async () => {
|
|
312
|
+
register('stdin-test', async ({ args, stdin }) => ({
|
|
313
|
+
stdout: `Received: ${stdin}\n`,
|
|
314
|
+
code: 0,
|
|
315
|
+
}));
|
|
316
|
+
|
|
317
|
+
const result = await $`echo "test input" | stdin-test`;
|
|
318
|
+
expect(result.stdout).toBe('Received: test input\n\n');
|
|
319
|
+
|
|
320
|
+
// Cleanup
|
|
321
|
+
unregister('stdin-test');
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
describe('Shell Settings Integration', () => {
|
|
326
|
+
test('should respect verbose setting for virtual commands', async () => {
|
|
327
|
+
register('verbose-test', async () => ({ stdout: 'output', code: 0 }));
|
|
328
|
+
|
|
329
|
+
const originalLog = console.log;
|
|
330
|
+
const logs = [];
|
|
331
|
+
console.log = (...args) => logs.push(args.join(' '));
|
|
332
|
+
|
|
333
|
+
try {
|
|
334
|
+
shell.verbose(true);
|
|
335
|
+
await $`verbose-test arg1 arg2`;
|
|
336
|
+
|
|
337
|
+
expect(logs.some((log) => log.includes('verbose-test arg1 arg2'))).toBe(
|
|
338
|
+
true
|
|
339
|
+
);
|
|
340
|
+
} finally {
|
|
341
|
+
console.log = originalLog;
|
|
342
|
+
unregister('verbose-test');
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
test('should respect xtrace setting for virtual commands', async () => {
|
|
347
|
+
register('trace-test', async () => ({ stdout: 'output', code: 0 }));
|
|
348
|
+
|
|
349
|
+
const originalLog = console.log;
|
|
350
|
+
const logs = [];
|
|
351
|
+
console.log = (...args) => logs.push(args.join(' '));
|
|
352
|
+
|
|
353
|
+
try {
|
|
354
|
+
shell.xtrace(true);
|
|
355
|
+
await $`trace-test`;
|
|
356
|
+
|
|
357
|
+
expect(logs.some((log) => log.startsWith('+ trace-test'))).toBe(true);
|
|
358
|
+
} finally {
|
|
359
|
+
console.log = originalLog;
|
|
360
|
+
unregister('trace-test');
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
});
|