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