@@ -647,28 +647,90 @@ pub fn find_test_only_dependencies(
647647}
648648
649649/// Check whether a package is listed in root deps or in the workspace that owns `file_path`.
650+ ///
651+ /// The owning workspace is the nearest ancestor directory tracked in `ws_dep_map`.
652+ /// When a file lives inside a tracked workspace but also inside a nested directory
653+ /// that has its own `package.json` (e.g. `packages/themes/my-theme/package.json`
654+ /// discovered outside the glob-matched workspace set), that nested manifest is
655+ /// probed first. This prevents the intermediate glob-matched workspace
656+ /// (`packages/themes`) from masking the actual owning package's declared deps.
650657pub fn is_package_listed_for_file (
651658 file_path : & Path ,
652659 package_name : & str ,
653660 root_deps : & FxHashSet < String > ,
654661 ws_dep_map : & [ ( PathBuf , FxHashSet < String > ) ] ,
655662) -> bool {
656- if let Some ( ws_deps) = owning_workspace_deps ( file_path, ws_dep_map) {
657- return ws_deps. contains ( package_name) ;
663+ if let Some ( ws_root) = owning_workspace_root ( file_path, ws_dep_map) {
664+ // Walk from the file's parent up to (but not past) the matched workspace root.
665+ // If a closer package.json exists, use its deps for the check so that nested
666+ // packages not declared as workspace entries are still attributed correctly.
667+ if let Some ( deps) = nearest_undeclared_package_json_deps ( file_path, ws_root, ws_dep_map) {
668+ return deps. contains ( package_name) ;
669+ }
670+
671+ // Fall back to the matched workspace's declared dep set.
672+ if let Some ( ws_deps) = ws_dep_map
673+ . iter ( )
674+ . find ( |( r, _) | r == ws_root)
675+ . map ( |( _, d) | d)
676+ {
677+ return ws_deps. contains ( package_name) ;
678+ }
658679 }
659680
660681 root_deps. contains ( package_name)
661682}
662683
663- fn owning_workspace_deps < ' a > (
684+ /// Return the root path of the deepest tracked workspace that is an ancestor of `file_path`.
685+ fn owning_workspace_root < ' a > (
664686 file_path : & Path ,
665687 ws_dep_map : & ' a [ ( PathBuf , FxHashSet < String > ) ] ,
666- ) -> Option < & ' a FxHashSet < String > > {
688+ ) -> Option < & ' a PathBuf > {
667689 ws_dep_map
668690 . iter ( )
669691 . filter ( |( ws_root, _) | file_path. starts_with ( ws_root) )
670692 . max_by_key ( |( ws_root, _) | ws_root. components ( ) . count ( ) )
671- . map ( |( _, ws_deps) | ws_deps)
693+ . map ( |( ws_root, _) | ws_root)
694+ }
695+
696+ /// Walk ancestor directories of `file_path` from the file's parent down to
697+ /// (but not past) `workspace_root`, looking for a `package.json` that is NOT
698+ /// already tracked in `ws_dep_map`.
699+ ///
700+ /// Returns the loaded dependency set when such a closer manifest is found.
701+ /// This handles the case where a glob like `./packages/*` discovers
702+ /// `packages/themes` as a workspace, but `packages/themes/my-theme` has its
703+ /// own `package.json` that was not expanded by the glob. The nested manifest
704+ /// is the actual owning package for any file beneath it.
705+ fn nearest_undeclared_package_json_deps (
706+ file_path : & Path ,
707+ workspace_root : & Path ,
708+ ws_dep_map : & [ ( PathBuf , FxHashSet < String > ) ] ,
709+ ) -> Option < FxHashSet < String > > {
710+ let file_dir = file_path. parent ( ) ?;
711+ for ancestor in file_dir. ancestors ( ) {
712+ // Stop once we reach or pass the matched workspace root.
713+ if ancestor == workspace_root {
714+ break ;
715+ }
716+ if !ancestor. starts_with ( workspace_root) {
717+ break ;
718+ }
719+ // Skip directories that are already tracked in ws_dep_map; those are
720+ // handled by the normal max-depth lookup.
721+ if ws_dep_map. iter ( ) . any ( |( r, _) | r == ancestor) {
722+ break ;
723+ }
724+ let pkg_path = ancestor. join ( "package.json" ) ;
725+ if let Ok ( pkg) = PackageJson :: load ( & pkg_path) {
726+ let mut deps: FxHashSet < String > = pkg. all_dependency_names ( ) . into_iter ( ) . collect ( ) ;
727+ if let Some ( name) = pkg. name {
728+ deps. insert ( name) ;
729+ }
730+ return Some ( deps) ;
731+ }
732+ }
733+ None
672734}
673735
674736/// Check if a corresponding `@types/<package>` is listed in dependencies.
0 commit comments