diff --git a/src/lint_cmd.rs b/src/lint_cmd.rs index 15f3fed..a7f6c71 100644 --- a/src/lint_cmd.rs +++ b/src/lint_cmd.rs @@ -525,7 +525,7 @@ fn filter_mypy_output(output: &str) -> String { } /// Filter generic linter output (fallback for non-ESLint linters) -fn filter_generic_lint(output: &str) -> String { +pub(crate) fn filter_generic_lint(output: &str) -> String { let mut warnings = 0; let mut errors = 0; let mut issues: Vec = Vec::new(); diff --git a/src/main.rs b/src/main.rs index fcb3930..6e2d945 100644 --- a/src/main.rs +++ b/src/main.rs @@ -657,6 +657,14 @@ enum PnpmCommands { #[arg(trailing_var_arg = true, allow_hyphen_values = true)] args: Vec, }, + /// Run a script with smart routing to specialized filters + Run { + /// Script name (e.g., test, lint, typecheck) + script: String, + /// Additional script arguments + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] + args: Vec, + }, /// Passthrough: runs any unsupported pnpm subcommand directly #[command(external_subcommand)] Other(Vec), @@ -961,8 +969,20 @@ fn main() -> Result<()> { PnpmCommands::Typecheck { args } => { tsc_cmd::run(&args, cli.verbose)?; } + PnpmCommands::Run { script, args } => { + pnpm_cmd::run_script(&script, &args, cli.verbose, cli.skip_env)?; + } PnpmCommands::Other(args) => { - pnpm_cmd::run_passthrough(&args, cli.verbose)?; + let first = args.first().and_then(|a| a.to_str()).unwrap_or(""); + if pnpm_cmd::is_pnpm_script(first) { + let str_args: Vec = args[1..] + .iter() + .filter_map(|a| a.to_str().map(String::from)) + .collect(); + pnpm_cmd::run_script(first, &str_args, cli.verbose, cli.skip_env)?; + } else { + pnpm_cmd::run_passthrough(&args, cli.verbose)?; + } } }, @@ -1546,4 +1566,60 @@ mod tests { _ => panic!("Expected Git Commit command"), } } + + #[test] + fn test_pnpm_run_basic() { + let cli = Cli::try_parse_from(["rtk", "pnpm", "run", "test"]).unwrap(); + match cli.command { + Commands::Pnpm { + command: PnpmCommands::Run { script, args }, + } => { + assert_eq!(script, "test"); + assert!(args.is_empty()); + } + _ => panic!("Expected Pnpm Run command"), + } + } + + #[test] + fn test_pnpm_run_with_args() { + let cli = + Cli::try_parse_from(["rtk", "pnpm", "run", "vitest", "--reporter=verbose"]).unwrap(); + match cli.command { + Commands::Pnpm { + command: PnpmCommands::Run { script, args }, + } => { + assert_eq!(script, "vitest"); + assert_eq!(args, vec!["--reporter=verbose"]); + } + _ => panic!("Expected Pnpm Run command"), + } + } + + #[test] + fn test_pnpm_run_colon_script() { + let cli = Cli::try_parse_from(["rtk", "pnpm", "run", "test:e2e"]).unwrap(); + match cli.command { + Commands::Pnpm { + command: PnpmCommands::Run { script, args }, + } => { + assert_eq!(script, "test:e2e"); + assert!(args.is_empty()); + } + _ => panic!("Expected Pnpm Run command"), + } + } + + #[test] + fn test_pnpm_shorthand_falls_to_other() { + let cli = Cli::try_parse_from(["rtk", "pnpm", "test"]).unwrap(); + match cli.command { + Commands::Pnpm { + command: PnpmCommands::Other(args), + } => { + assert_eq!(args[0], "test"); + } + _ => panic!("Expected Pnpm Other command"), + } + } } diff --git a/src/pnpm_cmd.rs b/src/pnpm_cmd.rs index f839942..2f8ec75 100644 --- a/src/pnpm_cmd.rs +++ b/src/pnpm_cmd.rs @@ -1,5 +1,7 @@ use crate::tracking; use anyhow::{Context, Result}; +use lazy_static::lazy_static; +use regex::Regex; use serde::Deserialize; use std::collections::HashMap; use std::ffi::OsString; @@ -512,6 +514,267 @@ pub fn run_passthrough(args: &[OsString], verbose: u8) -> Result<()> { Ok(()) } +// ─── pnpm run