use crate::ASTRA_STD_LIBS;
pub async fn find_first_lua_match_with_content(
lua: &mlua::Lua,
module_name: &str,
) -> Option<(std::path::PathBuf, String)> {
let lua_path: String;
if let Ok(path) = lua.load("return package.path").eval::<String>() {
lua_path = path
} else {
lua_path = "?".to_string();
}
let module_path = module_name.replace(".", std::path::MAIN_SEPARATOR_STR);
for pattern in lua_path.split(';').filter(|s| !s.is_empty()) {
let pattern = pattern.replacen('?', &module_path, 1).replacen(
&(".".to_owned() + std::path::MAIN_SEPARATOR_STR),
"",
1,
);
let pattern_path = std::path::PathBuf::from(&pattern);
let pattern_path_without_extension =
std::path::PathBuf::from(&pattern.replace(".luau", "").replace(".lua", ""));
let candidates = vec![
pattern_path.with_extension("lua"),
pattern_path.with_extension("luau"),
pattern_path_without_extension.join("init.lua"),
pattern_path_without_extension.join("init.luau"),
pattern_path_without_extension.join("d.lua"),
pattern_path_without_extension.join("d.luau"),
pattern_path.clone(), ];
for candidate in candidates.iter() {
if let Ok(content) = tokio::fs::read_to_string(&candidate).await {
return Some((candidate.clone(), content));
}
}
for candidate in &candidates {
let file_path = if let Ok(file_path) = candidate.strip_prefix(format!(
".{}astra{}",
std::path::MAIN_SEPARATOR_STR,
std::path::MAIN_SEPARATOR_STR
)) {
file_path
} else if let Ok(file_path) =
candidate.strip_prefix(format!(".{}", std::path::MAIN_SEPARATOR_STR))
{
file_path
} else {
candidate
};
if let Some(file) = ASTRA_STD_LIBS.get_file(file_path)
&& let Some(content) = file.contents_utf8()
{
return Some((candidate.to_path_buf(), content.to_string()));
}
}
}
None
}
pub fn register_import_function(lua: &mlua::Lua) -> mlua::Result<()> {
lua.globals().set(
"require",
lua.create_async_function(|lua, path: String| async move {
let key_id = format!("ASTRA_INTERNAL__IMPORT_CACHE_{path}");
if let Ok(cache) = lua
.globals()
.get::<Option<mlua::RegistryKey>>(key_id.as_str())
&& let Some(key) = cache
{
lua.registry_value::<mlua::Value>(&key)
} else {
let astra_table = lua.globals().get::<mlua::Table>("Astra")?;
let current_script_path: String = astra_table.get::<String>("current_script")?;
#[allow(clippy::collapsible_else_if)]
if let Some((file_path, content)) =
find_first_lua_match_with_content(&lua, &path).await
{
let file_path = file_path
.to_string_lossy()
.replace("./", "")
.replace(".\\", "");
astra_table.set("current_script", file_path.clone())?;
let result = lua
.load(content)
.set_name(file_path)
.eval_async::<mlua::Value>()
.await?;
let key = lua.create_registry_value(&result)?;
lua.globals().set(key_id, Some(key))?;
astra_table.set("current_script", current_script_path)?;
Ok(result)
} else {
Err(mlua::Error::runtime(format!(
"Could not find the module {path}"
)))
}
}
})?,
)
}