fn filter_subtrees_with_selector(
        &self,
        selector: &TargetSelector,
    ) -> Result<HashMap<PackageName, PackageInclusionReason>, ResolutionError> {
        let mut entry_packages = HashMap::new();

        for (name, info) in self.pkg_graph.packages() {
            if let Some(parent_dir) = selector.parent_dir.as_deref() {
                let path = parent_dir.to_unix();
                let parent_dir_matcher = wax::Glob::new(path.as_str())?;
                let matches = parent_dir_matcher.is_match(info.package_path().as_path());

                if matches {
                    entry_packages.insert(
                        name.to_owned(),
                        PackageInclusionReason::InFilteredDirectory {
                            directory: parent_dir.to_owned(),
                        },
                    );
                }
            } else {
                entry_packages.insert(
                    name.to_owned(),
                    PackageInclusionReason::IncludedByFilter {
                        filters: vec![selector.raw.to_string()],
                    },
                );
            }
        }

        // if we have a filter, use it to filter the entry packages
        let filtered_entry_packages = if !selector.name_pattern.is_empty() {
            match_package_names(&selector.name_pattern, &self.all_packages(), entry_packages)?
        } else {
            entry_packages
        };

        let mut roots = HashMap::new();
        let mut matched = HashSet::new();
        let changed_packages = if let Some(git_range) = selector.git_range.as_ref() {
            self.packages_changed_in_range(git_range)?
        } else {
            HashMap::default()
        };

        for (package, reason) in filtered_entry_packages {
            if matched.contains(&package) {
                roots.insert(package, reason);
                continue;
            }

            let workspace_node = package_graph::PackageNode::Workspace(package.clone());
            let dependencies = self.pkg_graph.dependencies(&workspace_node);

            for changed_package in changed_packages.keys() {
                if !selector.exclude_self && package.eq(changed_package) {
                    roots.insert(package, reason);
                    break;
                }

                let changed_node =
                    package_graph::PackageNode::Workspace(changed_package.to_owned());

                if dependencies.contains(&changed_node) {
                    roots.insert(package.clone(), reason);
                    matched.insert(package);
                    break;
                }
            }
        }

        Ok(roots)
    }
returns the set of nodes where the node or any of its dependencies match
the selector.

Example:
a -> b -> c
a -> d

filter(b) = {a, b, c}
filter(d) = {a, d}
crates/turborepo-lib/src/run/scope/filter.rs