Enhance syncback functionality and improve code readability

- Refactored the syncback process to streamline directory management and improve handling of class transitions in clean mode.
- Updated the `clone_tree_filtered` function to accept a tuple of compiled Globs and original pattern strings, enhancing flexibility in ignore pattern handling.
- Simplified logic for checking if paths are inside removed directories, improving code clarity.
- Added detailed comments to clarify the purpose of new logic for handling script directory transitions, ensuring better maintainability.
- Improved logging for better traceability during syncback operations.
This commit is contained in:
Joe 2026-02-01 20:10:11 -06:00
parent 1534a54808
commit 411f79ee81
10 changed files with 232 additions and 65 deletions

View file

@ -374,7 +374,8 @@ pub fn syncback_project<'sync>(
if old_inst.class_name() != new_inst.class {
// In clean mode, allow recoverable class transitions
// (e.g., Folder -> ModuleScript by creating init.luau)
let can_recover = can_transition_class(old_inst.class_name().as_str(), new_inst.class.as_str());
let can_recover =
can_transition_class(old_inst.class_name().as_str(), new_inst.class.as_str());
if !snapshot.data.is_incremental() && can_recover {
log::debug!(
"Clean mode: allowing class transition {} -> {} for {}",
@ -490,6 +491,31 @@ pub fn syncback_project<'sync>(
);
middleware = Middleware::Dir;
}
// Case 3: Filesystem has a script-dir but new instance is a DIFFERENT script type.
// e.g., ModuleScriptDir (init.luau) but new instance is Script → use ServerScriptDir.
// Without this, changing a ModuleScript to Script in Studio would silently keep
// the old init.luau file, causing the script to be read as ModuleScript on next build.
if is_script_dir_middleware {
let correct_middleware = match new_inst.class.as_str() {
"ModuleScript" => Some(Middleware::ModuleScriptDir),
"Script" => Some(Middleware::ServerScriptDir),
"LocalScript" => Some(Middleware::LocalScriptDir),
_ => None,
};
if let Some(new_middleware) = correct_middleware {
if middleware != new_middleware {
log::debug!(
"Clean mode: overriding {:?}->{:?} middleware for {} (class {} changed)",
middleware,
new_middleware,
full_path.display(),
new_inst.class
);
middleware = new_middleware;
}
}
}
}
descendant_snapshots.push(

View file

@ -74,7 +74,8 @@ pub fn syncback_rbxm<'sync>(
/// Clones a subtree from the source WeakDom, filtering out instances that match
/// the provided ignoreTrees glob patterns.
pub fn clone_tree_filtered(source: &WeakDom, root_ref: Ref, ignore_globs: &[Glob]) -> WeakDom {
/// Each entry contains both the compiled Glob and the original pattern string.
pub fn clone_tree_filtered(source: &WeakDom, root_ref: Ref, ignore_globs: &[(Glob, String)]) -> WeakDom {
let root_inst = source.get_by_ref(root_ref).expect("root ref should exist");
// Create a new tree with the root instance
@ -93,7 +94,7 @@ fn add_children_filtered(
source: &WeakDom,
parent_ref: Ref,
builder: &mut InstanceBuilder,
ignore_globs: &[Glob],
ignore_globs: &[(Glob, String)],
) {
let parent = source
.get_by_ref(parent_ref)
@ -103,7 +104,7 @@ fn add_children_filtered(
let child_path = inst_path(source, child_ref);
// Check if this child should be ignored
let should_ignore = ignore_globs.iter().any(|glob| glob.is_match(&child_path));
let should_ignore = ignore_globs.iter().any(|(glob, _)| glob.is_match(&child_path));
if should_ignore {
log::debug!("Filtering out {child_path} from rbxm due to ignoreTrees pattern");