diff --git a/crates/vt_workspace/src/package_filter.rs b/crates/vt_workspace/src/package_filter.rs index 8948f3c43..07e34df5e 100644 --- a/crates/vt_workspace/src/package_filter.rs +++ b/crates/vt_workspace/src/package_filter.rs @@ -403,11 +403,17 @@ impl PackageQueryArgs { PackageQuery::filters(Vec1::new(PackageFilter { exclude: false, selector: PackageSelector::Name(PackageNamePattern::Exact { - name, + name: name.clone(), unique: true, }), traversal, - source: None, + // The specifier's package name is user-typed, so it + // carries a source like a --filter token: a typo then + // joins the unmatched-selector warning and the + // --fail-if-no-match strict error instead of silently + // emptying the graph (synthetic filters stay + // source-less). + source: Some(name), })), false, )) @@ -1243,6 +1249,35 @@ mod tests { assert_eq!(f.source.as_deref(), Some("@test/app...")); } + #[test] + fn specifier_package_name_sets_source() { + // `vp run #`: the explicit package name is user-typed, so the + // compiled filter must carry it as `source` — otherwise a typo'd package + // is skipped by the unmatched-selector warning and `--fail-if-no-match`, + // and the run silently exits 0. + let cwd: Arc = Arc::from(abs("/workspace")); + let args = PackageQueryArgs { + recursive: false, + transitive: false, + workspace_root: false, + filters: Vec::new(), + fail_if_no_match: false, + }; + let (query, _) = args.into_package_query(Some(Str::from("@test/app")), &cwd).unwrap(); + match &query.0 { + crate::package_graph::PackageQueryKind::Filters(filters) => { + assert_eq!(filters.len(), 1); + assert_exact_name(&filters[0], "@test/app"); + assert_eq!( + filters[0].source.as_deref(), + Some("@test/app"), + "explicit specifier package must carry a source" + ); + } + crate::package_graph::PackageQueryKind::All => panic!("expected Filters, got All"), + } + } + #[test] fn filter_source_preserved_after_whitespace_split() { let cwd: Arc = Arc::from(abs("/workspace"));