tsconfig_includes/
path.rs1use std::{
2 error::Error,
3 fmt::Display,
4 path::{self, Path, PathBuf},
5};
6
7#[derive(Debug)]
8#[non_exhaustive]
9pub struct StripPrefixError {
10 absolute_path: PathBuf,
11 kind: StripPrefixErrorKind,
12}
13
14impl Display for StripPrefixError {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 match &self.kind {
17 StripPrefixErrorKind::Strip { ancestor, inner: _ } => write!(
18 f,
19 "cannot strip prefix {:?} from path {:?}",
20 ancestor, self.absolute_path
21 ),
22 StripPrefixErrorKind::PrefixNotFound { prefix } => write!(
23 f,
24 "never encountered prefix {:?} in path {:?}",
25 prefix, self.absolute_path
26 ),
27 }
28 }
29}
30
31impl Error for StripPrefixError {
32 fn source(&self) -> Option<&(dyn Error + 'static)> {
33 match &self.kind {
34 StripPrefixErrorKind::Strip { ancestor: _, inner } => Some(inner),
35 StripPrefixErrorKind::PrefixNotFound { prefix: _ } => None,
36 }
37 }
38}
39
40#[derive(Debug)]
41pub enum StripPrefixErrorKind {
42 #[non_exhaustive]
43 Strip {
44 ancestor: PathBuf,
45 inner: path::StripPrefixError,
46 },
47 #[non_exhaustive]
48 PrefixNotFound { prefix: PathBuf },
49}
50
51pub(crate) fn remove_relative_path_prefix_from_absolute_path(
53 prefix: &Path,
54 absolute_path: &Path,
55) -> Result<PathBuf, StripPrefixError> {
56 (|| {
57 for ancestor in absolute_path.ancestors() {
58 if ancestor.ends_with(prefix) {
59 let relative_path = absolute_path
60 .strip_prefix(ancestor)
61 .map(ToOwned::to_owned)
62 .map_err(|inner| StripPrefixErrorKind::Strip {
63 ancestor: ancestor.to_owned(),
64 inner,
65 })?;
66 return Ok(relative_path);
67 }
68 }
69
70 return Err(StripPrefixErrorKind::PrefixNotFound {
71 prefix: prefix.to_owned(),
72 })?;
73 })()
74 .map_err(|kind| StripPrefixError {
75 absolute_path: absolute_path.to_owned(),
76 kind,
77 })
78}
79
80pub(crate) fn is_glob(string: &str) -> bool {
81 string.contains('*')
82}
83
84pub(crate) fn glob_file_extension(glob: &str) -> Option<String> {
85 if glob.ends_with('*') {
86 return None;
87 }
88 Some(
89 glob.rsplit('*')
90 .next()
91 .expect("Expected glob to contain an asterisk")
92 .to_owned(),
93 )
94}
95
96pub(crate) fn is_monorepo_file(monorepo_root: &Path, file: &Path) -> bool {
97 for ancestor in file.ancestors() {
98 if ancestor.ends_with(monorepo_root) {
99 return true;
100 }
101 }
102 false
103}
104
105pub(crate) fn is_child_of_node_modules(file: &Path) -> bool {
106 for ancestor in file.ancestors() {
107 if ancestor.ends_with("node_modules") {
108 return true;
109 }
110 }
111 false
112}