roan_engine/module/loaders/mod.rs
1use crate::{
2 context::Context,
3 module::{loaders::ident::ModuleIdentifier, Module},
4};
5use std::{fmt::Debug, path::PathBuf};
6use tracing::debug;
7
8pub mod ident;
9
10/// Trait that defines the interface for a module loader.
11pub trait ModuleLoader: Debug {
12 /// Load a module from a given source.
13 fn load(&mut self, referrer: &Module, spec: &str, ctx: &Context) -> anyhow::Result<Module>;
14
15 /// Insert a module into the loader's cache if loader handles caching.
16 ///
17 /// This function is a no-op for loaders that do not cache modules.
18 ///
19 /// # Arguments
20 /// - `name` - The name of the module to insert into the cache.
21 /// - `module` - The module to insert into the cache.
22 fn insert(&mut self, name: String, module: Module) {}
23
24 /// Get a module from the cache if the loader caches modules.
25 ///
26 /// This function returns `None` for loaders that do not cache modules.
27 ///
28 /// # Arguments
29 /// - `name` - The name of the module to get from the cache.
30 fn get(&self, name: &str) -> Option<Module> {
31 None
32 }
33
34 /// Returns all the keys in the cache.
35 ///
36 /// This function returns an empty vector for loaders that do not cache modules.
37 ///
38 /// # Returns
39 /// A vector of strings representing the keys in the cache.
40 fn keys(&self) -> Vec<String> {
41 Vec::new()
42 }
43
44 /// Resolves the path of a referenced module based on the referrer module's path and the provided specification.
45 ///
46 /// # Arguments
47 ///
48 /// * `referrer` - A reference to the `Module` that provides the context for resolving the path.
49 /// * `spec` - A string slice that represents the specification of the path to resolve.
50 ///
51 /// # Returns
52 ///
53 /// A `Result<PathBuf>`, where the `Ok` variant contains the resolved path, and the `Err` variant
54 /// contains an error if the operation fails (e.g., if the `referrer` path has no parent).
55 ///
56 /// # Panics
57 ///
58 /// This function will panic if the `referrer` module's path has no parent directory.
59 fn resolve_referrer(&self, referrer: &Module, spec: &str) -> anyhow::Result<PathBuf> {
60 debug!("Resolving referrer: {:?}, spec: {}", referrer.path(), spec);
61 let referrer_path = referrer
62 .path()
63 .map_or_else(|| PathBuf::new(), |p| p.to_path_buf());
64 let dir = referrer_path.parent().expect("Module path has no parent");
65
66 let spec = if cfg!(windows) {
67 spec.replace("/", "\\")
68 } else {
69 spec.to_string()
70 };
71 let str_path = remove_surrounding_quotes(&spec);
72
73 let spec_path = PathBuf::from(str_path);
74
75 let path = if spec_path.is_absolute() {
76 spec_path
77 } else {
78 dir.join(spec_path)
79 };
80 debug!("Resolved path: {:?}", path);
81
82 Ok(path)
83 }
84}
85
86/// Removes surrounding double quotes from a string slice if present.
87pub fn remove_surrounding_quotes(s: &str) -> &str {
88 if s.starts_with('"') && s.ends_with('"') && s.len() >= 2 {
89 &s[1..s.len() - 1]
90 } else {
91 s
92 }
93}