diff --git a/src/discover/registry.rs b/src/discover/registry.rs index fafdaa8b..db3b9d89 100644 --- a/src/discover/registry.rs +++ b/src/discover/registry.rs @@ -1140,19 +1140,32 @@ mod tests { } #[test] - fn test_rewrite_npx_tsc() { - assert_eq!( - rewrite_command("npx tsc --noEmit", &[]), - Some("rtk tsc --noEmit".into()) - ); - } - - #[test] - fn test_rewrite_pnpm_tsc() { - assert_eq!( - rewrite_command("pnpm tsc --noEmit", &[]), - Some("rtk tsc --noEmit".into()) - ); + fn test_rewrite_tsc() { + let commands = vec![ + "npm exec tsc", + "npm rum tsc", + "npm run tsc", + "npm run-script tsc", + "npm urn tsc", + "npm x tsc", + "pnpm dlx tsc", + "pnpm exec tsc", + "pnpm run tsc", + "pnpm run-script tsc", + "npm tsc", + "npx tsc", + "pnpm tsc", + "pnpx tsc", + "tsc", + ]; + for command in commands { + assert_eq!( + rewrite_command(&format!("{command} --noEmit"), &[]), + Some("rtk tsc --noEmit".into()), + "Failed for command: {}", + command + ); + } } #[test] @@ -1172,19 +1185,61 @@ mod tests { } #[test] - fn test_rewrite_npx_playwright() { - assert_eq!( - rewrite_command("npx playwright test", &[]), - Some("rtk playwright test".into()) - ); + fn test_rewrite_playwright() { + let commands = vec![ + "npm exec playwright", + "npm rum playwright", + "npm run playwright", + "npm run-script playwright", + "npm urn playwright", + "npm x playwright", + "pnpm dlx playwright", + "pnpm exec playwright", + "pnpm run playwright", + "pnpm run-script playwright", + "npm playwright", + "npx playwright", + "pnpm playwright", + "pnpx playwright", + "playwright", + ]; + for command in commands { + assert_eq!( + rewrite_command(&format!("{command} test"), &[]), + Some("rtk playwright test".into()), + "Failed for command: {}", + command + ); + } } #[test] fn test_rewrite_next_build() { - assert_eq!( - rewrite_command("next build --turbo", &[]), - Some("rtk next --turbo".into()) - ); + let commands = vec![ + "npm exec next build", + "npm rum next build", + "npm run next build", + "npm run-script next build", + "npm urn next build", + "npm x next build", + "pnpm dlx next build", + "pnpm exec next build", + "pnpm run next build", + "pnpm run-script next build", + "npm next build", + "npx next build", + "pnpm next build", + "pnpx next build", + "next build", + ]; + for command in commands { + assert_eq!( + rewrite_command(&format!("{command} --turbo"), &[]), + Some("rtk next --turbo".into()), + "Failed for command: {}", + command + ); + } } #[test] @@ -1896,67 +1951,347 @@ mod tests { // --- JS/TS tooling --- #[test] - fn test_classify_vitest() { - assert!(matches!( - classify_command("vitest run"), - Classification::Supported { - rtk_equivalent: "rtk vitest", - .. - } - )); + fn test_classify_lint() { + let commands = vec![ + "npm exec biome", + "npm exec eslint", + "npm rum biome", + "npm rum eslint", + "npm rum lint", + "npm run biome", + "npm run eslint", + "npm run lint", + "npm run-script biome", + "npm run-script eslint", + "npm run-script lint", + "npm urn biome", + "npm urn eslint", + "npm urn lint", + "npm x biome", + "npm x eslint", + "pnpm dlx biome", + "pnpm dlx eslint", + "pnpm exec biome", + "pnpm exec eslint", + "pnpm run biome", + "pnpm run eslint", + "pnpm run lint", + "pnpm run-script biome", + "pnpm run-script eslint", + "pnpm run-script lint", + "npm biome", + "npm eslint", + "npm lint", + "npx biome", + "npx eslint", + "npx lint", + "pnpm biome", + "pnpm eslint", + "pnpm lint", + "pnpx biome", + "pnpx eslint", + "pnpx lint", + "biome", + "eslint", + "lint", + ]; + for command in commands { + assert!( + matches!( + classify_command(command), + Classification::Supported { + rtk_equivalent: "rtk lint", + .. + } + ), + "Failed for command: {}", + command + ); + } } #[test] - fn test_rewrite_vitest() { - assert_eq!( - rewrite_command("vitest run", &[]), - Some("rtk vitest run".into()) - ); + fn test_rewrite_lint() { + let commands = vec![ + "npm exec biome", + "npm exec eslint", + "npm rum biome", + "npm rum eslint", + "npm rum lint", + "npm run biome", + "npm run eslint", + "npm run lint", + "npm run-script biome", + "npm run-script eslint", + "npm run-script lint", + "npm urn biome", + "npm urn eslint", + "npm urn lint", + "npm x biome", + "npm x eslint", + "pnpm dlx biome", + "pnpm dlx eslint", + "pnpm exec biome", + "pnpm exec eslint", + "pnpm run biome", + "pnpm run eslint", + "pnpm run lint", + "pnpm run-script biome", + "pnpm run-script eslint", + "pnpm run-script lint", + "npm biome", + "npm eslint", + "npm lint", + "npx biome", + "npx eslint", + "npx lint", + "pnpm biome", + "pnpm eslint", + "pnpm lint", + "pnpx biome", + "pnpx eslint", + "pnpx lint", + "biome", + "eslint", + "lint", + ]; + for command in commands { + assert_eq!( + rewrite_command(command, &[]), + Some("rtk lint".into()), + "Failed for command: {}", + command + ); + } } #[test] - fn test_rewrite_pnpm_vitest() { - assert_eq!( - rewrite_command("pnpm vitest run", &[]), - Some("rtk vitest run".into()) - ); + fn test_classify_vitest() { + let commands = vec![ + "npm exec jest", + "npm exec vitest", + "npm rum jest", + "npm rum vitest", + "npm run jest", + "npm run vitest", + "npm run-script jest", + "npm run-script vitest", + "npm urn jest", + "npm urn vitest", + "npm x jest", + "npm x vitest", + "pnpm dlx jest", + "pnpm dlx vitest", + "pnpm exec jest", + "pnpm exec vitest", + "pnpm run jest", + "pnpm run vitest", + "pnpm run-script jest", + "pnpm run-script vitest", + "npm jest", + "npm t", + "npm test", + "npm tst", + "npm vitest", + "npx jest", + "npx vitest", + "pnpm jest", + "pnpm t", + "pnpm test", + "pnpm tst", + "pnpm vitest", + "pnpx jest", + "pnpx vitest", + "jest", + "vitest", + ]; + for command in commands { + assert!( + matches!( + classify_command(command), + Classification::Supported { + rtk_equivalent: "rtk vitest", + .. + } + ), + "Failed for command: {}", + command + ); + } + } + + #[test] + fn test_rewrite_vitest() { + let commands = vec![ + "npm exec jest", + "npm exec vitest", + "npm rum jest", + "npm rum vitest", + "npm run jest", + "npm run vitest", + "npm run-script jest", + "npm run-script vitest", + "npm urn jest", + "npm urn vitest", + "npm x jest", + "npm x vitest", + "pnpm dlx jest", + "pnpm dlx vitest", + "pnpm exec jest", + "pnpm exec vitest", + "pnpm run jest", + "pnpm run vitest", + "pnpm run-script jest", + "pnpm run-script vitest", + "npm jest", + "npm t", + "npm test", + "npm tst", + "npm vitest", + "npx jest", + "npx vitest", + "pnpm jest", + "pnpm t", + "pnpm test", + "pnpm tst", + "pnpm vitest", + "pnpx jest", + "pnpx vitest", + "jest", + "vitest", + ]; + for command in commands { + assert_eq!( + rewrite_command(&format!("{command} run"), &[]), + Some("rtk vitest run".into()), + "Failed for command: {}", + command + ); + } } #[test] fn test_classify_prisma() { - assert!(matches!( - classify_command("npx prisma migrate dev"), - Classification::Supported { - rtk_equivalent: "rtk prisma", - .. - } - )); + let commands = vec![ + "npm exec prisma", + "npm rum prisma", + "npm run prisma", + "npm run-script prisma", + "npm urn prisma", + "npm x prisma", + "pnpm dlx prisma", + "pnpm exec prisma", + "pnpm run prisma", + "pnpm run-script prisma", + "npm prisma", + "npx prisma", + "pnpm prisma", + "pnpx prisma", + "prisma", + ]; + for command in commands { + assert!( + matches!( + classify_command(format!("{command} migrate dev").as_str()), + Classification::Supported { + rtk_equivalent: "rtk prisma", + .. + } + ), + "Failed for command: {}", + command + ); + } } #[test] fn test_rewrite_prisma() { - assert_eq!( - rewrite_command("npx prisma migrate dev", &[]), - Some("rtk prisma migrate dev".into()) - ); + let commands = vec![ + "npm exec prisma", + "npm rum prisma", + "npm run prisma", + "npm run-script prisma", + "npm urn prisma", + "npm x prisma", + "pnpm dlx prisma", + "pnpm exec prisma", + "pnpm run prisma", + "pnpm run-script prisma", + "npm prisma", + "npx prisma", + "pnpm prisma", + "pnpx prisma", + "prisma", + ]; + for command in commands { + assert_eq!( + rewrite_command(format!("{command} migrate dev").as_str(), &[]), + Some("rtk prisma migrate dev".into()), + "Failed for command: {}", + command + ); + } } #[test] fn test_rewrite_prettier() { - assert_eq!( - rewrite_command("npx prettier --check src/", &[]), - Some("rtk prettier --check src/".into()) - ); + let commands = vec![ + "npm exec prettier", + "npm rum prettier", + "npm run prettier", + "npm run-script prettier", + "npm urn prettier", + "npm x prettier", + "pnpm dlx prettier", + "pnpm exec prettier", + "pnpm run prettier", + "pnpm run-script prettier", + "npm prettier", + "npx prettier", + "pnpm prettier", + "pnpx prettier", + "prettier", + ]; + for command in commands { + assert_eq!( + rewrite_command(format!("{command} --check src/").as_str(), &[]), + Some("rtk prettier --check src/".into()), + "Failed for command: {}", + command + ); + } } #[test] - fn test_rewrite_pnpm_list() { + fn test_rewrite_pnpm_command() { + let commands = vec![ + "build", + "exec", + "i", + "install", + "list", + "ls", + "outdated", + "run", + "run-script", + ]; + for command in commands { + assert_eq!( + rewrite_command(format!("pnpm {command}").as_str(), &[]), + Some(format!("rtk pnpm {command}")), + "Failed for command: pnpm {}", + command + ); + } + } + + #[test] + fn test_rewrite_npx() { assert_eq!( - rewrite_command("pnpm list", &[]), - Some("rtk pnpm list".into()) + rewrite_command(format!("npx svgo").as_str(), &[]), + Some(format!("rtk npx svgo")), ); } - // --- Compound operator edge cases --- #[test] diff --git a/src/discover/rules.rs b/src/discover/rules.rs index 44f19d60..5fcab1dc 100644 --- a/src/discover/rules.rs +++ b/src/discover/rules.rs @@ -16,20 +16,20 @@ pub const PATTERNS: &[&str] = &[ r"^git\s+(?:-[Cc]\s+\S+\s+)*(status|log|diff|show|add|commit|push|pull|branch|fetch|stash|worktree)", r"^gh\s+(pr|issue|run|repo|api|release)", r"^cargo\s+(build|test|clippy|check|fmt|install)", - r"^pnpm\s+(list|ls|outdated|install)", - r"^npm\s+(run|exec)", + r"^pnpm\s+(build|exec|i|install|list|ls|outdated|run|run-script)", + r"^npm\s+(exec|run|run-script|rum|urn|x)\s+", r"^npx\s+", r"^(cat|head|tail)\s+", r"^(rg|grep)\s+", r"^ls(\s|$)", r"^find\s+", - r"^(npx\s+|pnpm\s+)?tsc(\s|$)", - r"^(npx\s+|pnpm\s+)?(eslint|biome|lint)(\s|$)", - r"^(npx\s+|pnpm\s+)?prettier", - r"^(npx\s+|pnpm\s+)?next\s+build", - r"^(pnpm\s+|npx\s+)?(vitest|jest|test)(\s|$)", - r"^(npx\s+|pnpm\s+)?playwright", - r"^(npx\s+|pnpm\s+)?prisma", + r"^((p?np(m|x)|p?npm\s+(exec|run|run-script)|npm\s+(rum|urn|x)|pnpm\s+dlx)\s+)?tsc(\s|$)", + r"^((p?np(m|x)|p?npm\s+(exec|run|run-script)|npm\s+(rum|urn|x)|pnpm\s+dlx)\s+)?(biome|eslint|lint)(\s|$)", + r"^((p?np(m|x)|p?npm\s+(exec|run|run-script)|npm\s+(rum|urn|x)|pnpm\s+dlx)\s+)?prettier", + r"^((p?np(m|x)|p?npm\s+(exec|run|run-script)|npm\s+(rum|urn|x)|pnpm\s+dlx)\s+)?next\s+build", + r"^((p?np(m|x)|p?npm\s+(exec|run|run-script)|npm\s+(rum|urn|x)|pnpm\s+dlx)\s+)?(jest|t|tst|test|vitest)(\s|$)", + r"^((p?np(m|x)|p?npm\s+(exec|run|run-script)|npm\s+(rum|urn|x)|pnpm\s+dlx)\s+)?playwright", + r"^((p?np(m|x)|p?npm\s+(exec|run|run-script)|npm\s+(rum|urn|x)|pnpm\s+dlx)\s+)?prisma", r"^docker\s+(ps|images|logs|run|exec|build|compose\s+(ps|logs|build))", r"^kubectl\s+(get|logs|describe|apply)", r"^tree(\s|$)", @@ -177,7 +177,23 @@ pub const RULES: &[RtkRule] = &[ RtkRule { // Longest prefixes first for correct matching rtk_cmd: "rtk tsc", - rewrite_prefixes: &["pnpm tsc", "npx tsc", "tsc"], + rewrite_prefixes: &[ + "npm exec tsc", + "npm rum tsc", + "npm run tsc", + "npm run-script tsc", + "npm urn tsc", + "npm x tsc", + "pnpm dlx tsc", + "pnpm exec tsc", + "pnpm run tsc", + "pnpm run-script tsc", + "npm tsc", + "npx tsc", + "pnpm tsc", + "pnpx tsc", + "tsc", + ], category: "Build", savings_pct: 83.0, subcmd_savings: &[], @@ -186,11 +202,46 @@ pub const RULES: &[RtkRule] = &[ RtkRule { rtk_cmd: "rtk lint", rewrite_prefixes: &[ + "npm exec biome", + "npm exec eslint", + "npm rum biome", + "npm rum eslint", + "npm rum lint", + "npm run biome", + "npm run eslint", + "npm run lint", + "npm run-script biome", + "npm run-script eslint", + "npm run-script lint", + "npm urn biome", + "npm urn eslint", + "npm urn lint", + "npm x biome", + "npm x eslint", + "pnpm dlx biome", + "pnpm dlx eslint", + "pnpm exec biome", + "pnpm exec eslint", + "pnpm run biome", + "pnpm run eslint", + "pnpm run lint", + "pnpm run-script biome", + "pnpm run-script eslint", + "pnpm run-script lint", + "npm biome", + "npm eslint", + "npm lint", + "npx biome", "npx eslint", + "npx lint", + "pnpm biome", + "pnpm eslint", "pnpm lint", - "npx biome", - "eslint", + "pnpx biome", + "pnpx eslint", + "pnpx lint", "biome", + "eslint", "lint", ], category: "Build", @@ -200,7 +251,23 @@ pub const RULES: &[RtkRule] = &[ }, RtkRule { rtk_cmd: "rtk prettier", - rewrite_prefixes: &["npx prettier", "pnpm prettier", "prettier"], + rewrite_prefixes: &[ + "npm exec prettier", + "npm rum prettier", + "npm run prettier", + "npm run-script prettier", + "npm urn prettier", + "npm x prettier", + "pnpm dlx prettier", + "pnpm exec prettier", + "pnpm run prettier", + "pnpm run-script prettier", + "npm prettier", + "npx prettier", + "pnpm prettier", + "pnpx prettier", + "prettier", + ], category: "Build", savings_pct: 70.0, subcmd_savings: &[], @@ -209,7 +276,23 @@ pub const RULES: &[RtkRule] = &[ RtkRule { // "next build" is stripped to "rtk next" — the build subcommand is internal rtk_cmd: "rtk next", - rewrite_prefixes: &["npx next build", "pnpm next build", "next build"], + rewrite_prefixes: &[ + "npm exec next build", + "npm rum next build", + "npm run next build", + "npm run-script next build", + "npm urn next build", + "npm x next build", + "pnpm dlx next build", + "pnpm exec next build", + "pnpm run next build", + "pnpm run-script next build", + "npm next build", + "npx next build", + "pnpm next build", + "pnpx next build", + "next build", + ], category: "Build", savings_pct: 87.0, subcmd_savings: &[], @@ -217,7 +300,44 @@ pub const RULES: &[RtkRule] = &[ }, RtkRule { rtk_cmd: "rtk vitest", - rewrite_prefixes: &["pnpm vitest", "npx vitest", "vitest", "jest"], + rewrite_prefixes: &[ + "npm exec jest", + "npm exec vitest", + "npm rum jest", + "npm rum vitest", + "npm run jest", + "npm run vitest", + "npm run-script jest", + "npm run-script vitest", + "npm urn jest", + "npm urn vitest", + "npm x jest", + "npm x vitest", + "pnpm dlx jest", + "pnpm dlx vitest", + "pnpm exec jest", + "pnpm exec vitest", + "pnpm run jest", + "pnpm run vitest", + "pnpm run-script jest", + "pnpm run-script vitest", + "npm jest", + "npm t", + "npm test", + "npm tst", + "npm vitest", + "npx jest", + "npx vitest", + "pnpm jest", + "pnpm t", + "pnpm test", + "pnpm tst", + "pnpm vitest", + "pnpx jest", + "pnpx vitest", + "jest", + "vitest", + ], category: "Tests", savings_pct: 99.0, subcmd_savings: &[], @@ -225,7 +345,23 @@ pub const RULES: &[RtkRule] = &[ }, RtkRule { rtk_cmd: "rtk playwright", - rewrite_prefixes: &["npx playwright", "pnpm playwright", "playwright"], + rewrite_prefixes: &[ + "npm exec playwright", + "npm rum playwright", + "npm run playwright", + "npm run-script playwright", + "npm urn playwright", + "npm x playwright", + "pnpm dlx playwright", + "pnpm exec playwright", + "pnpm run playwright", + "pnpm run-script playwright", + "npm playwright", + "npx playwright", + "pnpm playwright", + "pnpx playwright", + "playwright", + ], category: "Tests", savings_pct: 94.0, subcmd_savings: &[], @@ -233,7 +369,23 @@ pub const RULES: &[RtkRule] = &[ }, RtkRule { rtk_cmd: "rtk prisma", - rewrite_prefixes: &["npx prisma", "pnpm prisma", "prisma"], + rewrite_prefixes: &[ + "npm exec prisma", + "npm rum prisma", + "npm run prisma", + "npm run-script prisma", + "npm urn prisma", + "npm x prisma", + "pnpm dlx prisma", + "pnpm exec prisma", + "pnpm run prisma", + "pnpm run-script prisma", + "npm prisma", + "npx prisma", + "pnpm prisma", + "pnpx prisma", + "prisma", + ], category: "Build", savings_pct: 88.0, subcmd_savings: &[],