fob_graph/
from_collection.rs1use std::collections::HashMap;
17use std::path::PathBuf;
18
19use thiserror::Error;
20
21use super::collection::{
22 CollectedExport, CollectedImportKind, CollectedImportSpecifier, CollectedModule,
23};
24use super::module::ExportsKind as FobExportsKind;
25use super::{
26 Export, ExportKind, Import, ImportKind, ImportSpecifier as FobImportSpecifier, ModuleId,
27 ModuleIdError, SourceSpan,
28};
29
30#[derive(Debug, Error)]
32pub enum CollectionGraphError {
33 #[error("failed to initialize module graph: {0}")]
35 GraphInitialization(String),
36
37 #[error("module id conversion failed for '{path}': {source}")]
39 ModuleIdConversion {
40 path: String,
41 #[source]
42 source: ModuleIdError,
43 },
44}
45
46pub struct PendingImport {
47 pub import: Import,
48 pub target: Option<String>,
49}
50
51pub fn convert_collected_module_id(path: &str) -> Result<ModuleId, CollectionGraphError> {
57 let path_buf = PathBuf::from(path);
58 ModuleId::new(&path_buf).map_err(|source| CollectionGraphError::ModuleIdConversion {
59 path: path.to_string(),
60 source,
61 })
62}
63
64pub fn convert_collected_exports(collected: &CollectedModule, module_id: &ModuleId) -> Vec<Export> {
65 let mut exports = Vec::new();
66
67 for export in &collected.exports {
68 match export {
69 CollectedExport::Named { exported, local: _ } => {
70 let kind = if exported == "default" {
71 ExportKind::Default
72 } else {
73 ExportKind::Named
74 };
75 exports.push(Export::new(
76 exported.clone(),
77 kind,
78 false, false, None, false, false, SourceSpan::new(module_id.as_path(), 0, 0),
84 ));
85 }
86 CollectedExport::Default => {
87 exports.push(Export::new(
88 "default".to_string(),
89 ExportKind::Default,
90 false,
91 false,
92 None,
93 false,
94 false,
95 SourceSpan::new(module_id.as_path(), 0, 0),
96 ));
97 }
98 CollectedExport::All { source } => {
99 exports.push(Export::new(
100 "*".to_string(),
101 ExportKind::StarReExport,
102 false,
103 false,
104 Some(source.clone()),
105 false,
106 false,
107 SourceSpan::new(module_id.as_path(), 0, 0),
108 ));
109 }
110 }
111 }
112
113 exports
114}
115
116pub fn convert_collected_imports(
117 collected: &CollectedModule,
118 module_id: &ModuleId,
119 _path_to_id: &HashMap<String, ModuleId>,
120) -> Vec<PendingImport> {
121 let mut imports = Vec::new();
122
123 for import in &collected.imports {
124 let specifiers = import
125 .specifiers
126 .iter()
127 .map(convert_import_specifier)
128 .collect();
129
130 let kind = match import.kind {
131 CollectedImportKind::Dynamic => ImportKind::Dynamic,
132 CollectedImportKind::Static => ImportKind::Static,
133 CollectedImportKind::TypeOnly => ImportKind::TypeOnly,
134 };
135
136 let fob_import = Import::new(
137 import.source.clone(),
138 specifiers,
139 kind,
140 None, SourceSpan::new(module_id.as_path(), 0, 0),
142 );
143
144 let target = if let Some(ref resolved_path) = import.resolved_path {
146 Some(resolved_path.clone())
148 } else {
149 Some(import.source.clone())
151 };
152
153 imports.push(PendingImport {
154 import: fob_import,
155 target,
156 });
157 }
158
159 imports
160}
161
162pub fn convert_import_specifier(spec: &CollectedImportSpecifier) -> FobImportSpecifier {
163 match spec {
164 CollectedImportSpecifier::Named { imported, local: _ } => {
165 FobImportSpecifier::Named(imported.clone())
166 }
167 CollectedImportSpecifier::Default { local: _ } => FobImportSpecifier::Default,
168 CollectedImportSpecifier::Namespace { local: _ } => {
169 FobImportSpecifier::Namespace("*".to_string())
170 }
171 }
172}
173
174pub fn infer_exports_kind(exports: &[CollectedExport]) -> FobExportsKind {
175 if exports.is_empty() {
177 FobExportsKind::None
178 } else {
179 FobExportsKind::Esm
180 }
181}
182
183pub fn has_star_export(exports: &[CollectedExport]) -> bool {
184 exports
185 .iter()
186 .any(|e| matches!(e, CollectedExport::All { .. }))
187}