Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
237 changes: 230 additions & 7 deletions src/rules/convert_require/rojo_sourcemap.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::path::{Path, PathBuf};
use std::path::{self, Path, PathBuf};

use serde::{Deserialize, Serialize};

use crate::utils::normalize_path;
use crate::{utils, DarkluaError};

use super::InstancePath;
Expand Down Expand Up @@ -31,7 +32,11 @@ impl RojoSourcemapNode {
while let Some(node) = queue.pop() {
node.id = index;
for file_path in &mut node.file_paths {
*file_path = utils::normalize_path(relative_to.join(&file_path));
if file_path.is_relative() {
*file_path =
path::absolute(utils::normalize_path(relative_to.join(&file_path)))
.expect("failed to convert to absolute path");
}
}
for child in &mut node.children {
child.parent_id = index;
Expand Down Expand Up @@ -128,8 +133,19 @@ impl RojoSourcemap {
let from_file = from_file.as_ref();
let target_file = target_file.as_ref();

let normalized = normalize_path(from_file.join(target_file));

let from_node = self.find_node(from_file)?;
let target_node = self.find_node(target_file)?;
let target_node = self.find_node(if from_file.has_root() {
log::trace!(
"in absolute require mode, normalized: {} -> {}",
from_file.display(),
normalized.display()
);
normalized.as_path()
} else {
target_file
})?;

let from_ancestors = self.hierarchy(from_node);
let target_ancestors = self.hierarchy(target_node);
Expand Down Expand Up @@ -219,10 +235,20 @@ impl RojoSourcemap {
ids
}

fn find_node(&self, path: &Path) -> Option<&RojoSourcemapNode> {
self.root_node
.iter()
.find(|node| node.file_paths.iter().any(|file_path| file_path == path))
fn find_node(&self, target_path: &Path) -> Option<&RojoSourcemapNode> {
let needle_path_buf = if !target_path.has_root() {
path::absolute(target_path).expect("failed")
} else {
target_path.to_path_buf()
};

let needle_path = needle_path_buf.as_path();

self.root_node.iter().find(|node| {
node.file_paths
.iter()
.any(|file_path| file_path.as_path() == needle_path)
})
}
}

Expand Down Expand Up @@ -277,6 +303,8 @@ mod test {
);
}

// Relative

#[test]
fn from_sibling_to_sibling_module() {
let sourcemap = new_sourcemap(
Expand Down Expand Up @@ -395,5 +423,200 @@ mod test {
script_path(&["parent"])
);
}

// Absolute

#[test]
fn abs_from_sibling_to_sibling_module() {
let sourcemap = new_sourcemap(
r#"{
"name": "Project",
"className": "ModuleScript",
"filePaths": ["C:/projects/thing/src/init.lua", "C:/projects/thing/default.project.json"],
"children": [
{
"name": "main",
"className": "ModuleScript",
"filePaths": ["C:/projects/thing/src/main.lua"]
},
{
"name": "value",
"className": "ModuleScript",
"filePaths": ["C:/projects/thing/src/value.lua"]
}
]
}"#,
);
pretty_assertions::assert_eq!(
sourcemap
.get_instance_path(
"C:/projects/thing/src/main.lua",
"C:/projects/thing/src/value.lua"
)
.unwrap(),
script_path(&["parent", "value"])
);
}

#[test]
fn abs_from_sibling_to_nested_sibling_module() {
let sourcemap = new_sourcemap(
r#"{
"name": "Project",
"className": "ModuleScript",
"filePaths": ["C:/projects/thing/src/init.lua", "C:/projects/thing/default.project.json"],
"children": [
{
"name": "main",
"className": "ModuleScript",
"filePaths": ["C:/projects/thing/src/main.lua"]
},
{
"name": "Lib",
"className": "Folder",
"children": [
{
"name": "format",
"className": "ModuleScript",
"filePaths": ["C:/projects/thing/src/Lib/format.lua"]
}
]
}
]
}"#,
);
pretty_assertions::assert_eq!(
sourcemap
.get_instance_path(
"C:/projects/thing/src/main.lua",
"C:/projects/thing/src/Lib/format.lua"
)
.unwrap(),
script_path(&["parent", "Lib", "format"])
);
}

#[test]
fn abs_from_child_require_parent() {
let sourcemap = new_sourcemap(
r#"{
"name": "Project",
"className": "ModuleScript",
"filePaths": ["C:/projects/thing/src/init.lua", "C:/projects/thing/default.project.json"],
"children": [
{
"name": "main",
"className": "ModuleScript",
"filePaths": ["C:/projects/thing/src/main.lua"]
}
]
}"#,
);
pretty_assertions::assert_eq!(
sourcemap
.get_instance_path(
"C:/projects/thing/src/main.lua",
"C:/projects/thing/src/init.lua"
)
.unwrap(),
script_path(&["parent"])
);
}

#[test]
fn abs_from_child_require_parent_nested() {
let sourcemap = new_sourcemap(
r#"{
"name": "Project",
"className": "ModuleScript",
"filePaths": ["C:/projects/thing/src/init.lua", "C:/projects/thing/default.project.json"],
"children": [
{
"name": "Sub",
"className": "ModuleScript",
"filePaths": ["C:/projects/thing/src/Sub/init.lua"],
"children": [
{
"name": "test",
"className": "ModuleScript",
"filePaths": ["C:/projects/thing/src/Sub/test.lua"]
}
]
}
]
}"#,
);
pretty_assertions::assert_eq!(
sourcemap
.get_instance_path(
"C:/projects/thing/src/Sub/test.lua",
"C:/projects/thing/src/Sub/init.lua"
)
.unwrap(),
script_path(&["parent"])
);
}

#[test]
fn rel_from_absolute() {
let sourcemap = new_sourcemap(
r#"{
"name": "Project",
"className": "ModuleScript",
"filePaths": ["C:/projects/thing/src/init.luau", "C:/projects/thing/default.project.json"],
"children": [
{
"name": "Sub",
"className": "ModuleScript",
"filePaths": ["C:/projects/thing/src/Sub/init.luau"],
"children": [
{
"name": "test",
"className": "ModuleScript",
"filePaths": ["C:/projects/thing/src/Sub/test.luau"]
}
]
}
]
}"#,
);
pretty_assertions::assert_eq!(
sourcemap
.get_instance_path("C:/projects/thing/src/Sub/test.luau", "../init.luau")
.unwrap(),
script_path(&["parent"])
);
}

#[test]
fn nested_rel_from_absolute() {
let sourcemap = new_sourcemap(
r#"{
"name": "Project",
"className": "ModuleScript",
"filePaths": ["C:/projects/thing/src/init.luau", "C:/projects/thing/default.project.json"],
"children": [
{
"name": "Sub",
"className": "ModuleScript",
"filePaths": ["C:/projects/thing/src/Sub/init.luau"],
"children": [
{
"name": "test",
"className": "ModuleScript",
"filePaths": ["C:/projects/thing/src/Sub/test.luau"]
}
]
}
]
}"#,
);
pretty_assertions::assert_eq!(
sourcemap
.get_instance_path("C:/projects/thing/src/Sub/test.luau", "../init.luau")
.unwrap(),
script_path(&["parent"])
);
}
}
}
4 changes: 4 additions & 0 deletions src/rules/require/path_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ pub(crate) fn get_relative_path(
source_path: &Path,
use_current_dir_prefix: bool,
) -> Result<Option<PathBuf>, DarkluaError> {
if require_path.is_absolute() {
return Ok(Some(require_path.to_path_buf()));
}

let source_parent = get_relative_parent_path(source_path);

if require_path.has_root() && !source_parent.has_root() {
Expand Down