use crate::js::module::ModulePath;
use crate::js::module::ModuleStatus;
use crate::js::module::es_module::*;
use crate::prelude::*;
use std::collections::hash_map::Entry;
use std::fmt::Debug;
#[derive(Clone)]
pub enum ImportKind {
Static,
Dynamic(v8::Global<v8::PromiseResolver>),
}
pub struct ModuleGraph {
kind: ImportKind,
root_rc: EsModuleRc,
same_origin: Vec<v8::Global<v8::PromiseResolver>>,
}
rc_refcell_ptr!(ModuleGraph);
impl Debug for ModuleGraph {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ModuleGraph")
.field(
"kind",
match self.kind {
ImportKind::Static => &"Static",
ImportKind::Dynamic(_) => &"Dynamic",
},
)
.field("root_rc", &self.root_rc)
.field(
"same_origin",
&format!("Vec<v8::PromiseResolver>({})", self.same_origin.len()),
)
.finish()
}
}
impl ModuleGraph {
pub fn kind(&self) -> &ImportKind {
&self.kind
}
pub fn root_rc(&self) -> EsModuleRc {
self.root_rc.clone()
}
pub fn same_origin(&self) -> &Vec<v8::Global<v8::PromiseResolver>> {
&self.same_origin
}
pub fn same_origin_mut(
&mut self,
) -> &mut Vec<v8::Global<v8::PromiseResolver>> {
&mut self.same_origin
}
}
impl ModuleGraph {
pub fn static_import(path: &str) -> ModuleGraph {
let module = EsModule::to_rc(EsModule::new(
path.into(),
ModuleStatus::Fetching,
vec![],
None,
false,
));
Self {
kind: ImportKind::Static,
root_rc: module,
same_origin: vec![],
}
}
pub fn dynamic_import(
path: &str,
promise: v8::Global<v8::PromiseResolver>,
) -> ModuleGraph {
let module = EsModule::to_rc(EsModule::new(
path.into(),
ModuleStatus::Fetching,
vec![],
None,
true,
));
Self {
kind: ImportKind::Dynamic(promise),
root_rc: module,
same_origin: vec![],
}
}
}
pub struct ModuleMap {
main: Option<ModulePath>,
by_path: FoldMap<ModulePath, v8::Global<v8::Module>>,
by_id: FoldMap<i32, Vec<(ModulePath, v8::Global<v8::Module>)>>,
pub seen: FoldMap<ModulePath, ModuleStatus>,
pub pending: Vec<ModuleGraphRc>,
}
impl Debug for ModuleMap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ModuleMap")
.field("main", &self.main)
.field(
"by_path",
&self
.by_path
.keys()
.map(|k| (k.clone(), "v8::Module".to_string()))
.collect::<FoldMap<String, String>>(),
)
.field(
"by_id",
&self
.by_id
.iter()
.map(|(k, v)| (*k, v.iter().map(|e| e.0.clone()).collect()))
.collect::<FoldMap<i32, Vec<String>>>(),
)
.field("seen", &self.seen)
.field("pending", &self.pending)
.finish()
}
}
impl ModuleMap {
pub fn new() -> ModuleMap {
Self {
main: None,
by_path: FoldMap::new(),
by_id: FoldMap::new(),
seen: FoldMap::new(),
pending: vec![],
}
}
pub fn main(&self) -> &Option<ModulePath> {
&self.main
}
pub fn insert(
&mut self,
path: &str,
module_id: i32,
module: v8::Global<v8::Module>,
) {
if self.main.is_none() && std::fs::metadata(path).is_ok() {
self.main = Some(path.into());
}
self.by_path.insert(path.into(), module.clone());
let entry = (path.into(), module.clone());
match self.by_id.entry(module_id) {
Entry::Vacant(value) => {
value.insert(vec![entry]);
}
Entry::Occupied(mut value) => {
value.get_mut().push(entry);
}
}
}
pub fn get(&self, path: &str) -> Option<v8::Global<v8::Module>> {
self.by_path.get(path).cloned()
}
pub fn contains(&self, path: &str) -> bool {
self.by_path.contains_key(path)
}
#[cfg(test)]
pub fn get_by_suffix(
&self,
path: &str,
) -> Option<(&ModulePath, &v8::Global<v8::Module>)> {
self.by_path.iter().find(|(k, _v)| {
let kp = Path::new(k).canonicalize().unwrap();
let pp = Path::new(path).canonicalize().unwrap();
kp.ends_with(&pp) || pp.ends_with(kp)
})
}
pub fn get_path(
&self,
module_id: i32,
module: v8::Global<v8::Module>,
) -> Option<ModulePath> {
match self.by_id.get(&module_id) {
None => None,
Some(entries) => {
if entries.len() <= 1 {
debug_assert!(!entries.is_empty());
Some(entries[0].0.clone())
} else {
entries
.iter()
.find(|(_, m)| *m == module)
.map(|(p, _)| p.clone())
}
}
}
}
}