typescript_tools/
query.rs

1use std::collections::HashMap;
2use std::fmt::Display;
3use std::path::{Path, PathBuf};
4
5use crate::configuration_file::ConfigurationFile;
6use crate::io::FromFileError;
7use crate::monorepo_manifest::{EnumeratePackageManifestsError, MonorepoManifest};
8
9#[derive(Debug)]
10#[non_exhaustive]
11pub struct QueryError {
12    pub kind: QueryErrorKind,
13}
14
15impl Display for QueryError {
16    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17        match &self.kind {
18            QueryErrorKind::PathInvalidUtf8(path) => {
19                write!(f, "path contains invalid UTF-8: {:?}", path)
20            }
21            _ => write!(f, "error querying monorepo dependencies"),
22        }
23    }
24}
25
26impl std::error::Error for QueryError {
27    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
28        match &self.kind {
29            QueryErrorKind::FromFile(err) => Some(err),
30            QueryErrorKind::EnumeratePackageManifests(err) => Some(err),
31            QueryErrorKind::PathInvalidUtf8(_) => None,
32        }
33    }
34}
35
36impl From<FromFileError> for QueryError {
37    fn from(err: FromFileError) -> Self {
38        Self {
39            kind: QueryErrorKind::FromFile(err),
40        }
41    }
42}
43
44impl From<EnumeratePackageManifestsError> for QueryError {
45    fn from(err: EnumeratePackageManifestsError) -> Self {
46        Self {
47            kind: QueryErrorKind::EnumeratePackageManifests(err),
48        }
49    }
50}
51
52#[derive(Debug)]
53pub enum QueryErrorKind {
54    #[non_exhaustive]
55    FromFile(FromFileError),
56    #[non_exhaustive]
57    EnumeratePackageManifests(EnumeratePackageManifestsError),
58    #[non_exhaustive]
59    PathInvalidUtf8(PathBuf),
60}
61
62#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
63pub enum InternalDependenciesFormat {
64    Name,
65    Path,
66}
67
68pub fn query_internal_dependencies<P>(
69    root: P,
70    format: InternalDependenciesFormat,
71) -> Result<HashMap<String, Vec<String>>, QueryError>
72where
73    P: AsRef<Path>,
74{
75    fn inner(
76        root: &Path,
77        format: InternalDependenciesFormat,
78    ) -> Result<HashMap<String, Vec<String>>, QueryError> {
79        let lerna_manifest = MonorepoManifest::from_directory(root)?;
80
81        let package_manifest_by_package_name =
82            lerna_manifest.package_manifests_by_package_name()?;
83
84        let internal_dependencies_by_package: HashMap<String, Vec<String>> =
85        package_manifest_by_package_name
86            .iter()
87            .map(
88                |(package_name, package_manifest)| -> Result<(String, Vec<String>), QueryError> {
89                    let key = match format {
90                        InternalDependenciesFormat::Name => package_name.as_str().to_owned(),
91                        InternalDependenciesFormat::Path => package_manifest
92                            .directory()
93                            .to_str()
94                            .map(ToOwned::to_owned)
95                            .ok_or_else(|| QueryError {
96                                kind: QueryErrorKind::PathInvalidUtf8(root.to_owned()),
97                            })?,
98                    };
99                    let values: Vec<String> = package_manifest
100                        .transitive_internal_dependency_package_names_exclusive(
101                            &package_manifest_by_package_name,
102                        )
103                        .into_iter()
104                        .map(|dependency| match format {
105                            InternalDependenciesFormat::Name => {
106                                Ok(dependency.contents.name.as_str().to_owned())
107                            }
108                            InternalDependenciesFormat::Path => dependency
109                                .directory()
110                                .to_str()
111                                .map(ToOwned::to_owned)
112                                .ok_or_else(|| QueryError {
113                                    kind: QueryErrorKind::PathInvalidUtf8(root.to_owned()),
114                                }),
115                        })
116                        .collect::<Result<_, _>>()?;
117
118                    Ok((key, values))
119                },
120            )
121            .collect::<Result<_, _>>()?;
122
123        Ok(internal_dependencies_by_package)
124    }
125    inner(root.as_ref(), format)
126}