Skip to content

Commit 51c3de3

Browse files
committed
fix(cli): prevent help pipe panic
1 parent 41e78e2 commit 51c3de3

3 files changed

Lines changed: 65 additions & 13 deletions

File tree

packages/cli/binding/src/cli/help.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ fn has_flag_before_terminator(args: &[String], flag: &str) -> bool {
5656
false
5757
}
5858

59+
pub(super) fn has_help_flag_before_terminator(args: &[String]) -> bool {
60+
args.iter()
61+
.take_while(|arg| arg.as_str() != "--")
62+
.any(|arg| matches!(arg.as_str(), "-h" | "--help"))
63+
}
64+
5965
pub(super) fn should_suppress_subcommand_stdout(subcommand: &SynthesizableSubcommand) -> bool {
6066
match subcommand {
6167
SynthesizableSubcommand::Lint { args } => has_flag_before_terminator(args, "--init"),
@@ -67,6 +73,15 @@ pub(super) fn should_suppress_subcommand_stdout(subcommand: &SynthesizableSubcom
6773
}
6874
}
6975

76+
pub(super) fn should_capture_help_stdout(subcommand: &SynthesizableSubcommand) -> bool {
77+
let args = match subcommand {
78+
SynthesizableSubcommand::Lint { args } | SynthesizableSubcommand::Fmt { args } => args,
79+
_ => return false,
80+
};
81+
82+
has_help_flag_before_terminator(args)
83+
}
84+
7085
pub(super) fn should_prepend_vitest_run(args: &[String]) -> bool {
7186
let Some(first_arg) = args.first().map(String::as_str) else {
7287
return true;
@@ -295,6 +310,25 @@ mod tests {
295310
assert!(!should_suppress_subcommand_stdout(&subcommand));
296311
}
297312

313+
#[test]
314+
fn lint_help_captures_stdout() {
315+
let subcommand = SynthesizableSubcommand::Lint { args: vec!["--help".to_string()] };
316+
assert!(should_capture_help_stdout(&subcommand));
317+
}
318+
319+
#[test]
320+
fn fmt_short_help_captures_stdout() {
321+
let subcommand = SynthesizableSubcommand::Fmt { args: vec!["-h".to_string()] };
322+
assert!(should_capture_help_stdout(&subcommand));
323+
}
324+
325+
#[test]
326+
fn help_after_terminator_is_not_captured() {
327+
let subcommand =
328+
SynthesizableSubcommand::Lint { args: vec!["--".to_string(), "--help".to_string()] };
329+
assert!(!should_capture_help_stdout(&subcommand));
330+
}
331+
298332
#[test]
299333
fn global_subcommands_produce_invalid_subcommand_error() {
300334
use clap::error::ErrorKind;

packages/cli/binding/src/cli/mod.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ use self::{
3333
execution::{FilterStream, resolve_and_execute, resolve_and_execute_with_filter},
3434
handler::{VitePlusCommandHandler, VitePlusConfigLoader},
3535
help::{
36-
handle_cli_parse_error, normalize_help_args, print_help, should_print_help,
37-
should_suppress_subcommand_stdout,
36+
handle_cli_parse_error, normalize_help_args, print_help, should_capture_help_stdout,
37+
should_print_help, should_suppress_subcommand_stdout,
3838
},
3939
types::CLIArgs,
4040
};
@@ -96,6 +96,18 @@ async fn execute_direct_subcommand(
9696
|_| Cow::Borrowed(""),
9797
)
9898
.await?
99+
} else if should_capture_help_stdout(&other) {
100+
resolve_and_execute_with_filter(
101+
&resolver,
102+
other,
103+
None,
104+
&envs,
105+
cwd,
106+
&cwd_arc,
107+
FilterStream::Stdout,
108+
|s| Cow::Borrowed(s),
109+
)
110+
.await?
99111
} else if matches!(&other, SynthesizableSubcommand::Fmt { .. }) {
100112
resolve_and_execute_with_filter(
101113
&resolver,

packages/cli/binding/src/cli/resolver.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use vite_task::config::user::{
88
};
99

1010
use super::{
11-
help::should_prepend_vitest_run,
11+
help::{has_help_flag_before_terminator, should_prepend_vitest_run},
1212
types::{CliOptions, ResolvedSubcommand, ResolvedUniversalViteConfig, SynthesizableSubcommand},
1313
};
1414

@@ -94,15 +94,18 @@ impl SubcommandResolver {
9494
.to_str()
9595
.ok_or_else(|| anyhow::anyhow!("lint JS path is not valid UTF-8"))?;
9696
let owned_resolved_vite_config;
97-
let resolved_vite_config = if let Some(config) = resolved_vite_config {
98-
config
97+
let resolved_vite_config = if has_help_flag_before_terminator(&args) {
98+
None
99+
} else if let Some(config) = resolved_vite_config {
100+
Some(config)
99101
} else {
100102
owned_resolved_vite_config = self.resolve_universal_vite_config().await?;
101-
&owned_resolved_vite_config
103+
Some(&owned_resolved_vite_config)
102104
};
103105

104-
if let (Some(_), Some(config_file)) =
105-
(&resolved_vite_config.lint, &resolved_vite_config.config_file)
106+
if let Some(resolved_vite_config) = resolved_vite_config
107+
&& let (Some(_), Some(config_file)) =
108+
(&resolved_vite_config.lint, &resolved_vite_config.config_file)
106109
{
107110
args.insert(0, "-c".to_string());
108111
args.insert(1, config_file.clone());
@@ -130,15 +133,18 @@ impl SubcommandResolver {
130133
.to_str()
131134
.ok_or_else(|| anyhow::anyhow!("fmt JS path is not valid UTF-8"))?;
132135
let owned_resolved_vite_config;
133-
let resolved_vite_config = if let Some(config) = resolved_vite_config {
134-
config
136+
let resolved_vite_config = if has_help_flag_before_terminator(&args) {
137+
None
138+
} else if let Some(config) = resolved_vite_config {
139+
Some(config)
135140
} else {
136141
owned_resolved_vite_config = self.resolve_universal_vite_config().await?;
137-
&owned_resolved_vite_config
142+
Some(&owned_resolved_vite_config)
138143
};
139144

140-
if let (Some(_), Some(config_file)) =
141-
(&resolved_vite_config.fmt, &resolved_vite_config.config_file)
145+
if let Some(resolved_vite_config) = resolved_vite_config
146+
&& let (Some(_), Some(config_file)) =
147+
(&resolved_vite_config.fmt, &resolved_vite_config.config_file)
142148
{
143149
args.insert(0, "-c".to_string());
144150
args.insert(1, config_file.clone());

0 commit comments

Comments
 (0)