fob_graph/memory/
construction.rs1use rustc_hash::FxHashMap as HashMap;
4
5use super::super::external_dep::ExternalDependency;
6use super::super::{Module, ModuleId};
7use super::graph::{GraphInner, ModuleGraph};
8use crate::{Error, Result};
9
10impl ModuleGraph {
11 pub fn new() -> Result<Self> {
13 Ok(Self {
14 inner: std::sync::Arc::new(parking_lot::RwLock::new(GraphInner::default())),
15 })
16 }
17
18 pub fn from_modules<I>(modules: I) -> Result<Self>
20 where
21 I: IntoIterator<Item = Module>,
22 {
23 let graph = Self::new()?;
24 for module in modules {
25 graph.add_module(module)?;
26 }
27 Ok(graph)
28 }
29
30 pub fn from_collected_data(
32 collection: super::super::collection::CollectionState,
33 ) -> Result<Self> {
34 use super::super::from_collection::{
35 PendingImport, convert_collected_exports, convert_collected_imports,
36 convert_collected_module_id, has_star_export, infer_exports_kind,
37 };
38 use super::super::module::ModuleFormat as FobModuleFormat;
39 use super::super::semantic::analyze_symbols;
40
41 let graph = Self::new()?;
42
43 let mut path_to_id: std::collections::HashMap<String, ModuleId> =
44 std::collections::HashMap::new();
45 let mut pending_modules: Vec<(ModuleId, Module, Vec<PendingImport>)> = Vec::new();
46
47 for entry in collection.modules.iter() {
49 let path = entry.key();
50 let collected = entry.value();
51 if collected.is_external {
52 continue;
53 }
54
55 let module_id = convert_collected_module_id(path)
56 .map_err(|e| Error::InvalidConfig(format!("Module ID conversion failed: {}", e)))?;
57 path_to_id.insert(path.clone(), module_id);
58 }
59
60 for entry in collection.modules.iter() {
62 let path = entry.key();
63 let collected = entry.value();
64 if collected.is_external {
65 continue;
66 }
67
68 let module_id = path_to_id.get(path).ok_or_else(|| {
69 Error::InvalidConfig(format!("Module ID not found for path: {}", path))
70 })?;
71
72 let exports = convert_collected_exports(collected, module_id);
73 let imports = convert_collected_imports(collected, module_id, &path_to_id);
74
75 let has_side_effects = collected.has_side_effects;
76
77 let source_type = super::super::SourceType::from_path(module_id.as_path());
79 let code = collected.code.as_deref().unwrap_or("");
80 let mut symbol_table = analyze_symbols(
81 code,
82 module_id.as_path().to_str().unwrap_or("unknown"),
83 source_type,
84 )
85 .unwrap_or_default();
86
87 let export_names: Vec<String> = exports.iter().map(|e| e.name.clone()).collect();
89 symbol_table.mark_exports(&export_names);
90
91 let mut builder = Module::builder(
92 module_id.clone(),
93 module_id.as_path().to_path_buf(),
94 source_type,
95 )
96 .exports(exports)
97 .side_effects(has_side_effects)
98 .original_size(code.len())
99 .bundled_size(None)
100 .external(false)
101 .symbol_table(symbol_table)
102 .module_format(FobModuleFormat::Unknown)
103 .exports_kind(infer_exports_kind(&collected.exports))
104 .has_star_exports(has_star_export(&collected.exports))
105 .execution_order(None);
106
107 if collected.is_entry {
108 builder = builder.entry(true);
109 }
110
111 let module = builder.build();
112 pending_modules.push((module_id.clone(), module, imports));
113 }
114
115 let mut external_aggregate: HashMap<String, ExternalDependency> = HashMap::default();
116
117 for (module_id, mut module, pending_imports) in pending_modules {
119 let mut resolved_imports = Vec::with_capacity(pending_imports.len());
120 for mut pending_import in pending_imports {
121 if let Some(target_path) = pending_import.target {
122 if let Some(target_id) = path_to_id.get(&target_path) {
123 pending_import.import.resolved_to = Some(target_id.clone());
124 graph.add_dependency(module_id.clone(), target_id.clone())?;
125 } else {
126 let dep = external_aggregate
128 .entry(target_path.clone())
129 .or_insert_with(|| ExternalDependency::new(target_path.clone()));
130 dep.push_importer(module_id.clone());
131 }
132 }
133 resolved_imports.push(pending_import.import);
134 }
135
136 module.imports = std::sync::Arc::new(resolved_imports);
138 graph.add_module(module)?;
139 }
140
141 for dep in external_aggregate.into_values() {
142 graph.add_external_dependency(dep)?;
143 }
144
145 Ok(graph)
146 }
147}