Walk up from `start_dir` for the nearest manifest declaring `name`; `extends` chains with cycle detection. */
(&mut self, name: &str, start_dir: &str)
| 134 | impl TestResolver { |
| 135 | /* Walk up from `start_dir` for the nearest manifest declaring `name`; `extends` chains with cycle detection. */ |
| 136 | fn resolve_bare(&mut self, name: &str, start_dir: &str) -> Result<Resolved, String> { |
| 137 | let mut visited: HashSet<String> = HashSet::new(); |
| 138 | let mut search_dir = start_dir.to_string(); |
| 139 | let mut hops = 0u32; |
| 140 | loop { |
| 141 | if hops > 32 { return Err(format!("packages.json walk-up exceeded 32 hops resolving '{}'", name)); } |
| 142 | hops += 1; |
| 143 | let mut hit: Option<(String, Option<String>, Option<String>)> = None; |
| 144 | for dir in walk_up_dirs(&search_dir) { |
| 145 | let s = self.state.borrow(); |
| 146 | if let Some(m) = s.manifests.get(&dir) { |
| 147 | let target = m.imports.iter().find(|(k, _)| k == name).map(|(_, v)| v.clone()); |
| 148 | let ext = m.extends.clone(); |
| 149 | drop(s); |
| 150 | hit = Some((dir, target, ext)); |
| 151 | break; |
| 152 | } |
| 153 | } |
| 154 | let Some((dir, target, ext)) = hit else { |
| 155 | return Err(format!( |
| 156 | "no packages.json above '{}' declares '{}'", start_dir, name)); |
| 157 | }; |
| 158 | if let Some(target) = target { |
| 159 | let canonical = join_relative(&dir, &target); |
| 160 | return self.resolve_canonical(&canonical); |
| 161 | } |
| 162 | if let Some(ext) = ext { |
| 163 | let m_spec = format!("{}packages.json", dir); |
| 164 | if !visited.insert(m_spec) { |
| 165 | return Err("circular extends chain in packages.json".to_string()); |
| 166 | } |
| 167 | let mut next = join_relative(&dir, &ext); |
| 168 | if !next.ends_with('/') { next.push('/'); } |
| 169 | search_dir = next; |
| 170 | continue; |
| 171 | } |
| 172 | return Err(format!("alias '{}' not declared in '{}packages.json'\nhelp: declare it, add \"extends\": \"..\" to inherit, or use a quoted path", name, dir)); |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | fn resolve_canonical(&self, spec: &str) -> Result<Resolved, String> { |
| 177 | let s = self.state.borrow(); |
no test coverage detected