pesde/src/linking/generator.rs

138 lines
4 KiB
Rust
Raw Normal View History

2024-07-17 19:38:01 +02:00
use std::path::{Component, Path};
2024-07-25 16:32:48 +02:00
use crate::manifest::target::TargetKind;
2024-07-17 19:38:01 +02:00
use full_moon::{ast::luau::ExportedTypeDeclaration, visitors::Visitor};
2024-07-25 16:32:48 +02:00
use relative_path::RelativePathBuf;
2024-07-17 19:38:01 +02:00
struct TypeVisitor {
types: Vec<String>,
}
impl Visitor for TypeVisitor {
fn visit_exported_type_declaration(&mut self, node: &ExportedTypeDeclaration) {
let name = node.type_declaration().type_name().to_string();
let (declaration_generics, generics) =
if let Some(declaration) = node.type_declaration().generics() {
let mut declaration_generics = vec![];
let mut generics = vec![];
for generic in declaration.generics().iter() {
declaration_generics.push(generic.to_string());
if generic.default_type().is_some() {
generics.push(generic.parameter().to_string())
} else {
generics.push(generic.to_string())
}
}
(
format!("<{}>", declaration_generics.join(", ")),
format!("<{}>", generics.join(", ")),
)
} else {
("".to_string(), "".to_string())
};
self.types.push(format!(
"export type {name}{declaration_generics} = module.{name}{generics}\n"
));
}
}
pub fn get_file_types(file: &str) -> Result<Vec<String>, Vec<full_moon::Error>> {
let ast = full_moon::parse(file)?;
let mut visitor = TypeVisitor { types: vec![] };
visitor.visit_ast(&ast);
Ok(visitor.types)
}
2024-07-25 16:32:48 +02:00
pub fn generate_lib_linking_module<I: IntoIterator<Item = S>, S: AsRef<str>>(
2024-07-17 19:38:01 +02:00
path: &str,
types: I,
) -> String {
let mut output = format!("local module = require({path})\n");
for ty in types {
output.push_str(ty.as_ref());
}
output.push_str("return module");
output
}
2024-07-25 16:32:48 +02:00
fn luau_style_path(path: &Path) -> String {
path.components()
.enumerate()
.filter_map(|(i, ct)| match ct {
Component::ParentDir => Some(if i == 0 {
".".to_string()
} else {
"..".to_string()
}),
Component::Normal(part) => Some(format!("{}", part.to_string_lossy())),
_ => None,
})
.collect::<Vec<_>>()
.join("/")
}
pub fn get_lib_require_path(
target: &TargetKind,
2024-07-17 19:38:01 +02:00
base_dir: &Path,
2024-07-25 16:32:48 +02:00
lib_file: &RelativePathBuf,
2024-07-17 19:38:01 +02:00
destination_dir: &Path,
use_new_structure: bool,
2024-07-25 16:32:48 +02:00
) -> String {
2024-07-17 19:38:01 +02:00
let path = pathdiff::diff_paths(destination_dir, base_dir).unwrap();
2024-07-25 16:32:48 +02:00
let path = if use_new_structure {
log::debug!("using new structure for require path");
2024-07-17 19:38:01 +02:00
lib_file.to_path(path)
} else {
2024-07-25 16:32:48 +02:00
log::debug!("using old structure for require path");
2024-07-17 19:38:01 +02:00
path
};
#[cfg(feature = "roblox")]
2024-07-25 16:32:48 +02:00
if matches!(target, TargetKind::Roblox) {
2024-07-17 19:38:01 +02:00
let path = path
.components()
.filter_map(|component| match component {
Component::ParentDir => Some(".Parent".to_string()),
Component::Normal(part) if part != "init.lua" && part != "init.luau" => {
Some(format!(
"[{:?}]",
part.to_string_lossy()
.trim_end_matches(".lua")
.trim_end_matches(".luau")
))
}
_ => None,
})
.collect::<Vec<_>>()
.join("");
2024-07-25 16:32:48 +02:00
return format!("script{path}");
2024-07-17 19:38:01 +02:00
};
2024-07-25 16:32:48 +02:00
format!("{:?}", luau_style_path(&path))
}
2024-07-17 19:38:01 +02:00
2024-07-25 16:32:48 +02:00
pub fn generate_bin_linking_module(path: &str) -> String {
format!("return require({path})")
2024-07-17 19:38:01 +02:00
}
2024-07-25 16:32:48 +02:00
pub fn get_bin_require_path(
base_dir: &Path,
bin_file: &RelativePathBuf,
destination_dir: &Path,
) -> String {
let path = pathdiff::diff_paths(destination_dir, base_dir).unwrap();
let path = bin_file.to_path(path);
2024-07-17 19:38:01 +02:00
2024-07-25 16:32:48 +02:00
format!("{:?}", luau_style_path(&path))
2024-07-17 19:38:01 +02:00
}