1use std::collections::{HashMap, HashSet};
2use std::path::{Path, PathBuf};
3
4use super::js_local::js_candidate_files;
5use super::predicates::ruby_require_root;
6use super::rust_local::{rust_candidate_files, rust_import_target, rust_qualified_call_target};
7
8mod apple;
9mod bindings;
10mod dotnet;
11mod elixir;
12mod jvm;
13mod package_metadata;
14mod python;
15mod scripting;
16
17pub(super) use bindings::JS_BUILTIN_MODULES;
18pub(crate) use bindings::{
19 ExternalCallTarget, ExternalImportBinding, ExternalRootBinding, ExtractedImports,
20 ImportBindings, LocalCallBinding,
21};
22pub(super) use package_metadata::{
23 build_go_package_files, load_dart_external_packages, load_dart_self_package_name,
24 load_go_module_path, load_js_external_packages, load_js_self_package_name,
25 load_rust_external_crates, load_rust_self_crate_name,
26};
27pub(super) use python::{build_python_module_index, python_candidate_files};
28
29pub(super) use apple::build_swift_module_files;
30use apple::{build_objc_indexes, objc_relative_import_file, swift_modules_for_rel};
31use dotnet::build_csharp_index;
32pub(super) use elixir::build_elixir_local_module_files;
33#[cfg(test)]
34pub(super) use elixir::load_elixir_dependency_names;
35use elixir::{build_elixir_local_module_roots, load_elixir_external_roots};
36use jvm::{build_java_class_index, build_kotlin_package_files, build_scala_package_files};
37pub(super) use scripting::build_php_symbol_files;
38use scripting::{build_lua_module_files, build_ruby_constant_files};
39
40#[derive(Debug, Clone, Default)]
41pub struct ImportResolutionContext {
42 pub(super) python_modules: HashSet<String>,
43 pub(super) js_external_packages: HashSet<String>,
44 pub(super) js_self_package_name: Option<String>,
45 pub(super) go_module_path: Option<String>,
46 pub(super) go_package_files: HashMap<String, Vec<String>>,
51 pub(super) rust_external_crates: HashSet<String>,
52 pub(super) rust_self_crate_name: Option<String>,
53 pub(super) java_local_classes: HashSet<String>,
54 pub(super) java_class_files: HashMap<String, Vec<String>>,
59 pub(super) csharp_local_roots: HashSet<String>,
60 pub(super) csharp_type_files: HashMap<String, Vec<String>>,
66 pub(super) kotlin_package_files: HashMap<String, Vec<String>>,
73 pub(super) scala_package_files: HashMap<String, Vec<String>>,
80 pub(super) lua_module_files: HashMap<String, Vec<String>>,
86 pub(super) objc_import_files: HashMap<String, Vec<String>>,
91 pub(super) objc_file_types: HashMap<String, Vec<String>>,
95 pub(super) objc_file_functions: HashMap<String, Vec<String>>,
99 pub(super) php_local_symbols: HashSet<String>,
100 pub(super) php_symbol_files: HashMap<String, Vec<String>>,
108 pub(super) ruby_local_constant_roots: HashSet<String>,
109 pub(super) ruby_constant_files: HashMap<String, Vec<String>>,
116 pub(super) ruby_require_root_overrides: HashMap<String, String>,
117 pub(super) swift_local_modules: HashSet<String>,
118 pub(super) swift_module_files: HashMap<String, Vec<String>>,
124 pub(super) dart_external_packages: HashSet<String>,
125 pub(super) dart_self_package_name: Option<String>,
126 pub(super) elixir_external_roots: HashMap<String, String>,
127 pub(super) elixir_external_root_overrides: HashMap<String, String>,
128 pub(super) elixir_local_module_roots: HashSet<String>,
129 pub(super) elixir_module_files: HashMap<String, Vec<String>>,
138}
139
140impl ImportResolutionContext {
141 pub(super) fn js_candidate_files(&self, rel_path: &str, specifier: &str) -> Vec<String> {
145 js_candidate_files(rel_path, self.js_self_package_name.as_deref(), specifier)
146 }
147
148 pub(super) fn rust_import_candidate(
152 &self,
153 rel_path: &str,
154 path: &str,
155 ) -> Option<LocalCallBinding> {
156 let target = rust_import_target(
157 rel_path,
158 self.rust_self_crate_name.as_deref(),
159 &self.rust_external_crates,
160 path,
161 )?;
162 Some(LocalCallBinding::named(
163 rust_candidate_files(&target.source_root, &target.module),
164 target.name,
165 ))
166 }
167
168 pub(super) fn rust_qualified_candidate(
171 &self,
172 rel_path: &str,
173 qualifier_path: &str,
174 name: &str,
175 ) -> Option<LocalCallBinding> {
176 let target = rust_qualified_call_target(
177 rel_path,
178 self.rust_self_crate_name.as_deref(),
179 &self.rust_external_crates,
180 qualifier_path,
181 name,
182 )?;
183 Some(LocalCallBinding::named(
184 rust_candidate_files(&target.source_root, &target.module),
185 target.name,
186 ))
187 }
188
189 pub(super) fn go_candidate_files(&self, module: &str) -> Vec<String> {
195 let Some(self_module) = self.go_module_path.as_deref() else {
196 return Vec::new();
197 };
198 let dir = if module == self_module {
199 String::new()
200 } else if let Some(rest) = module.strip_prefix(&format!("{self_module}/")) {
201 rest.to_string()
202 } else {
203 return Vec::new();
204 };
205 self.go_package_files.get(&dir).cloned().unwrap_or_default()
206 }
207
208 pub(super) fn java_candidate_files(&self, fqcn: &str) -> Vec<String> {
213 self.java_class_files.get(fqcn).cloned().unwrap_or_default()
214 }
215
216 pub(super) fn csharp_type_files(&self, type_path: &str) -> Vec<String> {
221 self.csharp_type_files
222 .get(type_path)
223 .cloned()
224 .unwrap_or_default()
225 }
226
227 pub(super) fn kotlin_package_files(&self, package: &str) -> Vec<String> {
232 self.kotlin_package_files
233 .get(package)
234 .cloned()
235 .unwrap_or_default()
236 }
237
238 pub(super) fn scala_package_files(&self, package: &str) -> Vec<String> {
242 self.scala_package_files
243 .get(package)
244 .cloned()
245 .unwrap_or_default()
246 }
247
248 pub(super) fn lua_module_files(&self, module: &str) -> Vec<String> {
249 self.lua_module_files
250 .get(module)
251 .cloned()
252 .unwrap_or_default()
253 }
254
255 pub(super) fn objc_import_candidate_files(
256 &self,
257 rel_path: &str,
258 import_path: &str,
259 ) -> Vec<String> {
260 let mut files = Vec::new();
261 if let Some(relative) = objc_relative_import_file(rel_path, import_path) {
262 files.push(relative);
263 }
264 if let Some(mapped) = self.objc_import_files.get(import_path) {
265 files.extend(mapped.iter().cloned());
266 }
267 if let Some(name) = Path::new(import_path)
268 .file_name()
269 .and_then(|name| name.to_str())
270 && let Some(mapped) = self.objc_import_files.get(name)
271 {
272 files.extend(mapped.iter().cloned());
273 }
274 files.sort();
275 files.dedup();
276 files
277 }
278
279 pub(super) fn objc_declared_types(&self, rel_path: &str) -> Vec<String> {
280 self.objc_file_types
281 .get(rel_path)
282 .cloned()
283 .unwrap_or_default()
284 }
285
286 pub(super) fn objc_declared_functions(&self, rel_path: &str) -> Vec<String> {
287 self.objc_file_functions
288 .get(rel_path)
289 .cloned()
290 .unwrap_or_default()
291 }
292
293 pub(super) fn php_candidate_files(&self, name: &str) -> Vec<String> {
298 self.php_symbol_files
299 .get(&name.trim_start_matches('\\').to_ascii_lowercase())
300 .cloned()
301 .unwrap_or_default()
302 }
303
304 pub(super) fn swift_module_candidate_files(&self, rel_path: &str) -> Vec<String> {
310 let mut files = swift_modules_for_rel(Path::new(rel_path))
311 .iter()
312 .filter_map(|module| self.swift_module_files.get(module))
313 .flatten()
314 .cloned()
315 .collect::<Vec<_>>();
316 files.sort();
317 files.dedup();
318 files
319 }
320
321 pub(super) fn ruby_require_root(&self, required: &str) -> Option<&str> {
322 self.ruby_require_root_overrides
323 .get(required)
324 .map(String::as_str)
325 .or_else(|| ruby_require_root(required))
326 }
327
328 pub(super) fn ruby_constant_files(&self, root: &str) -> Vec<String> {
329 self.ruby_constant_files
330 .get(root)
331 .cloned()
332 .unwrap_or_default()
333 }
334
335 pub(super) fn elixir_external_root_module(&self, root: &str) -> Option<&str> {
336 self.elixir_external_root_overrides
337 .get(root)
338 .or_else(|| self.elixir_external_roots.get(root))
339 .map(String::as_str)
340 }
341
342 pub(super) fn elixir_module_files(&self, module: &str) -> Vec<String> {
346 self.elixir_module_files
347 .get(module)
348 .cloned()
349 .unwrap_or_default()
350 }
351}
352
353pub fn build_import_resolution_context(
354 root_path: &Path,
355 candidate_files: &[PathBuf],
356) -> ImportResolutionContext {
357 build_import_resolution_context_with_overrides(
358 root_path,
359 candidate_files,
360 HashMap::new(),
361 HashMap::new(),
362 )
363}
364
365pub fn build_import_resolution_context_with_overrides(
366 root_path: &Path,
367 candidate_files: &[PathBuf],
368 ruby_require_root_overrides: HashMap<String, String>,
369 elixir_external_root_overrides: HashMap<String, String>,
370) -> ImportResolutionContext {
371 let java_index = build_java_class_index(root_path, candidate_files);
372 let csharp_index = build_csharp_index(root_path, candidate_files);
373 let ruby_constant_files = build_ruby_constant_files(root_path, candidate_files);
374 let php_symbol_files = build_php_symbol_files(root_path, candidate_files);
375 let swift_module_files = build_swift_module_files(root_path, candidate_files);
376 let objc_index = build_objc_indexes(root_path, candidate_files);
377 ImportResolutionContext {
378 python_modules: build_python_module_index(root_path, candidate_files),
379 js_external_packages: load_js_external_packages(root_path),
380 js_self_package_name: load_js_self_package_name(root_path),
381 go_module_path: load_go_module_path(root_path),
382 go_package_files: build_go_package_files(root_path, candidate_files),
383 rust_external_crates: load_rust_external_crates(root_path),
384 rust_self_crate_name: load_rust_self_crate_name(root_path),
385 java_local_classes: java_index.local_classes,
386 java_class_files: java_index.class_files,
387 csharp_local_roots: csharp_index.local_roots,
388 csharp_type_files: csharp_index.type_files,
389 kotlin_package_files: build_kotlin_package_files(root_path, candidate_files),
390 scala_package_files: build_scala_package_files(root_path, candidate_files),
391 lua_module_files: build_lua_module_files(root_path, candidate_files),
392 objc_import_files: objc_index.import_files,
393 objc_file_types: objc_index.file_types,
394 objc_file_functions: objc_index.file_functions,
395 php_local_symbols: php_symbol_files.keys().cloned().collect(),
396 php_symbol_files,
397 ruby_local_constant_roots: ruby_constant_files.keys().cloned().collect(),
398 ruby_constant_files,
399 ruby_require_root_overrides,
400 swift_local_modules: swift_module_files.keys().cloned().collect(),
401 swift_module_files,
402 dart_external_packages: load_dart_external_packages(root_path),
403 dart_self_package_name: load_dart_self_package_name(root_path),
404 elixir_external_roots: load_elixir_external_roots(root_path),
405 elixir_external_root_overrides,
406 elixir_local_module_roots: build_elixir_local_module_roots(candidate_files),
407 elixir_module_files: build_elixir_local_module_files(root_path, candidate_files),
408 }
409}