node_resolver/
package_json.rs1use std::cell::RefCell;
4use std::collections::HashMap;
5use std::path::Path;
6use std::path::PathBuf;
7
8use deno_package_json::PackageJson;
9use deno_package_json::PackageJsonCacheResult;
10use deno_package_json::PackageJsonRc;
11use sys_traits::FsMetadata;
12use sys_traits::FsRead;
13
14use crate::errors::PackageJsonLoadError;
15
16pub trait NodePackageJsonCache:
17 deno_package_json::PackageJsonCache
18 + std::fmt::Debug
19 + deno_maybe_sync::MaybeSend
20 + deno_maybe_sync::MaybeSync
21{
22 fn as_deno_package_json_cache(
23 &self,
24 ) -> &dyn deno_package_json::PackageJsonCache;
25}
26
27impl<T> NodePackageJsonCache for T
28where
29 T: deno_package_json::PackageJsonCache
30 + std::fmt::Debug
31 + deno_maybe_sync::MaybeSend
32 + deno_maybe_sync::MaybeSync,
33{
34 fn as_deno_package_json_cache(
35 &self,
36 ) -> &dyn deno_package_json::PackageJsonCache {
37 self
38 }
39}
40
41#[allow(clippy::disallowed_types)]
42pub type PackageJsonCacheRc =
43 deno_maybe_sync::MaybeArc<dyn NodePackageJsonCache>;
44
45thread_local! {
46 static CACHE: RefCell<HashMap<PathBuf, PackageJsonRc>> = RefCell::new(HashMap::new());
47}
48
49#[derive(Debug)]
50pub struct PackageJsonThreadLocalCache;
51
52impl PackageJsonThreadLocalCache {
53 pub fn clear() {
54 CACHE.with_borrow_mut(|cache| cache.clear());
55 }
56}
57
58impl deno_package_json::PackageJsonCache for PackageJsonThreadLocalCache {
59 fn get(&self, path: &Path) -> PackageJsonCacheResult {
60 CACHE.with_borrow(|cache| match cache.get(path).cloned() {
61 Some(value) => PackageJsonCacheResult::Hit(Some(value)),
62 None => PackageJsonCacheResult::NotCached,
63 })
64 }
65
66 fn set(&self, path: PathBuf, package_json: Option<PackageJsonRc>) {
67 let Some(package_json) = package_json else {
68 return;
70 };
71 CACHE.with_borrow_mut(|cache| cache.insert(path, package_json));
72 }
73}
74
75#[allow(clippy::disallowed_types)]
76pub type PackageJsonResolverRc<TSys> =
77 deno_maybe_sync::MaybeArc<PackageJsonResolver<TSys>>;
78
79#[derive(Debug)]
80pub struct PackageJsonResolver<TSys: FsRead + FsMetadata> {
81 sys: TSys,
82 loader_cache: Option<PackageJsonCacheRc>,
83}
84
85impl<TSys: FsRead + FsMetadata> PackageJsonResolver<TSys> {
86 pub fn new(sys: TSys, loader_cache: Option<PackageJsonCacheRc>) -> Self {
87 Self { sys, loader_cache }
88 }
89
90 pub fn get_closest_package_json(
91 &self,
92 file_path: &Path,
93 ) -> Result<Option<PackageJsonRc>, PackageJsonLoadError> {
94 self.get_closest_package_jsons(file_path).next().transpose()
95 }
96
97 pub fn get_closest_package_jsons<'a>(
100 &'a self,
101 file_path: &'a Path,
102 ) -> ClosestPackageJsonsIterator<'a, TSys> {
103 ClosestPackageJsonsIterator {
104 current_path: file_path,
105 resolver: self,
106 }
107 }
108
109 pub fn load_package_json(
110 &self,
111 path: &Path,
112 ) -> Result<Option<PackageJsonRc>, PackageJsonLoadError> {
113 let result = PackageJson::load_from_path(
114 &self.sys,
115 self
116 .loader_cache
117 .as_deref()
118 .map(|cache| cache.as_deno_package_json_cache()),
119 path,
120 );
121 match result {
122 Ok(pkg_json) => Ok(pkg_json),
123 Err(err) => Err(PackageJsonLoadError(err)),
124 }
125 }
126}
127
128pub struct ClosestPackageJsonsIterator<'a, TSys: FsRead + FsMetadata> {
129 current_path: &'a Path,
130 resolver: &'a PackageJsonResolver<TSys>,
131}
132
133impl<'a, TSys: FsRead + FsMetadata> Iterator
134 for ClosestPackageJsonsIterator<'a, TSys>
135{
136 type Item = Result<PackageJsonRc, PackageJsonLoadError>;
137
138 fn next(&mut self) -> Option<Self::Item> {
139 while let Some(parent) = self.current_path.parent() {
140 self.current_path = parent;
141 let package_json_path = parent.join("package.json");
142 match self.resolver.load_package_json(&package_json_path) {
143 Ok(Some(value)) => return Some(Ok(value)),
144 Ok(None) => {
145 }
147 Err(err) => return Some(Err(err)),
148 }
149 }
150 None
151 }
152}