harn_modules/
namespace_imports.rs1use std::collections::BTreeMap;
4use std::path::{Path, PathBuf};
5
6use crate::package_imports::resolve_import_path_with_snapshots;
7use crate::package_snapshot::PackageSnapshot;
8use crate::{decl_site, normalize_path, DefKind, DefSite, ImportRef, ModuleGraph, ModuleInfo};
9
10#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct NamespaceImportInfo {
13 pub alias: String,
14 pub raw_path: String,
15 pub resolved_path: Option<PathBuf>,
16 pub member_names: Vec<String>,
18 pub member_kinds: BTreeMap<String, DefKind>,
20}
21
22impl ModuleGraph {
23 pub fn namespace_imports_for_file(&self, file: &Path) -> Option<Vec<NamespaceImportInfo>> {
29 let file = normalize_path(file);
30 let module = self.modules.get(&file)?;
31 if module.has_unresolved_namespace_import {
32 return None;
33 }
34
35 let mut out = Vec::new();
36 for import in &module.imports {
37 let Some(alias) = &import.namespace_alias else {
38 continue;
39 };
40 let (member_names, member_kinds) = match &import.path {
41 Some(import_path) => {
42 let imported = self
43 .modules
44 .get(import_path)
45 .or_else(|| self.modules.get(&normalize_path(import_path)))?;
46 if imported.load_error.is_some() {
47 return None;
48 }
49 let mut names: Vec<String> = imported.exports.iter().cloned().collect();
50 names.sort();
51 let mut kinds = BTreeMap::new();
52 for name in &names {
53 if let Some(kind) = self.exported_kind(import_path, name) {
54 kinds.insert(name.clone(), kind);
55 }
56 }
57 (names, kinds)
58 }
59 None => (Vec::new(), BTreeMap::new()),
60 };
61 out.push(NamespaceImportInfo {
62 alias: alias.clone(),
63 raw_path: import.raw_path.clone(),
64 resolved_path: import.path.as_ref().map(|path| normalize_path(path)),
65 member_names,
66 member_kinds,
67 });
68 }
69 Some(out)
70 }
71
72 pub fn namespace_member_lookup(
77 &self,
78 file: &Path,
79 alias: &str,
80 member: &str,
81 ) -> Option<DefSite> {
82 let file = normalize_path(file);
83 let module = self.modules.get(&file)?;
84 let target = module
85 .imports
86 .iter()
87 .find(|import| import.namespace_alias.as_deref() == Some(alias))
88 .and_then(|import| import.path.as_ref())
89 .or_else(|| module.namespace_re_exports.get(alias))?;
90 self.exported_kind(target, member)?;
91 self.export_definition_of(target, member)
92 .or_else(|| self.definition_of(target, member))
93 }
94}
95
96pub(crate) fn record_namespace_import(
98 module: &mut ModuleInfo,
99 file: &Path,
100 span: harn_lexer::Span,
101 alias: &str,
102 path: &str,
103 is_pub: bool,
104 package_snapshots: &[PackageSnapshot],
105) {
106 let import_path = resolve_import_path_with_snapshots(file, path, package_snapshots);
107 if import_path.is_none() {
108 module.has_unresolved_namespace_import = true;
109 }
110 module.declarations.insert(
115 alias.to_string(),
116 decl_site(file, span, alias, DefKind::Variable),
117 );
118 if is_pub {
119 module.own_exports.insert(alias.to_string());
120 module.exports.insert(alias.to_string());
121 if let Some(resolved) = &import_path {
122 module
123 .namespace_re_exports
124 .insert(alias.to_string(), normalize_path(resolved));
125 }
126 }
127 module.imports.push(ImportRef {
128 raw_path: path.to_string(),
129 path: import_path,
130 selective_names: None,
131 namespace_alias: Some(alias.to_string()),
132 import_span: span,
133 });
134}