typescript_tools/
query.rs1use 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}