diff --git a/src/change_processor.rs b/src/change_processor.rs index 3c6e9fc3..8f78a09a 100644 --- a/src/change_processor.rs +++ b/src/change_processor.rs @@ -15,7 +15,7 @@ use crate::{ apply_patch_set, compute_patch_set, AppliedPatchSet, InstigatingSource, PatchSet, RojoTree, }, snapshot_middleware::{snapshot_from_vfs, snapshot_project_node}, - syncback::{deduplicate_name, name_needs_slugify, slugify_name}, + syncback::{name_needs_slugify, slugify_name}, }; /// Processes file change events, updates the DOM, and sends those updates @@ -311,42 +311,6 @@ impl JobThreadContext { } } - /// Deduplicate a slugified name against existing entries in a parent - /// directory. Reads the directory, strips entries to bare slugs (file_stem), - /// and uses `deduplicate_name` to find a collision-free name. - fn dedup_against_dir(slug: &str, parent_dir: &Path, exclude: Option<&str>) -> String { - let mut taken = std::collections::HashSet::new(); - if let Ok(entries) = fs::read_dir(parent_dir) { - for entry in entries.flatten() { - let name = entry.file_name(); - let name_str = name.to_string_lossy(); - // Use file_stem as a rough bare-slug approximation. - // For directories this is the dir name itself; for files - // it strips the last extension (e.g., "foo.server" from - // "foo.server.luau"). This is conservative: it may over- - // dedup in rare cases (compound extensions) but never - // under-dedup. - let stem = if entry.path().is_dir() { - name_str.to_string() - } else { - std::path::Path::new(name_str.as_ref()) - .file_stem() - .and_then(|s| s.to_str()) - .unwrap_or(&name_str) - .to_string() - }; - // Exclude the entry being renamed (it will be gone after rename) - if let Some(ex) = exclude { - if name_str == ex { - continue; - } - } - taken.insert(stem.to_lowercase()); - } - } - deduplicate_name(slug, &taken) - } - /// Computes and applies patches to the DOM for a given file path. /// /// This function finds the nearest ancestor to the given path that has associated instances @@ -759,22 +723,12 @@ impl JobThreadContext { .and_then(|f| f.to_str()) .unwrap_or(""); // Slugify the new name for filesystem safety - let mut slugified_new_name = + let slugified_new_name = if name_needs_slugify(new_name) { slugify_name(new_name) } else { new_name.to_string() }; - // Dedup against siblings to avoid overwriting - // an existing directory at the target path - let candidate = grandparent.join(&slugified_new_name); - if candidate.exists() && candidate != dir_path { - slugified_new_name = Self::dedup_against_dir( - &slugified_new_name, - grandparent, - dir_path.file_name().and_then(|s| s.to_str()), - ); - } let new_dir_path = grandparent.join(&slugified_new_name); @@ -862,33 +816,12 @@ impl JobThreadContext { &stem[..stem.len() - script_suffix.len()] }; - let mut slugified_new_name = - if name_needs_slugify(new_name) { - slugify_name(new_name) - } else { - new_name.to_string() - }; - // Dedup against siblings to avoid overwriting - // an existing file at the target path - let test_file_name = if extension.is_empty() { - format!("{}{}", slugified_new_name, script_suffix) + let slugified_new_name = if name_needs_slugify(new_name) + { + slugify_name(new_name) } else { - format!( - "{}{}.{}", - slugified_new_name, script_suffix, extension - ) + new_name.to_string() }; - let test_path = parent.join(&test_file_name); - if test_path.exists() && test_path != *path { - let old_filename = path - .file_name() - .and_then(|s| s.to_str()); - slugified_new_name = Self::dedup_against_dir( - &slugified_new_name, - parent, - old_filename, - ); - } let new_file_name = if extension.is_empty() { format!("{}{}", slugified_new_name, script_suffix) } else { diff --git a/src/web/api.rs b/src/web/api.rs index 8a5345db..12d87e5b 100644 --- a/src/web/api.rs +++ b/src/web/api.rs @@ -574,10 +574,7 @@ impl ApiService { adds_by_parent.entry(parent_ref).or_default().push(added); } else { // No parent — process individually (will fail with context) - adds_by_parent - .entry(Ref::none()) - .or_default() - .push(added); + adds_by_parent.entry(Ref::none()).or_default().push(added); } } for (parent_ref, siblings) in &adds_by_parent { @@ -1954,8 +1951,7 @@ impl ApiService { indexmap::IndexMap::new(), indexmap::IndexMap::new(), ); - let meta_path = - parent_dir.join(format!("{}.meta.json5", encoded_name)); + let meta_path = parent_dir.join(format!("{}.meta.json5", encoded_name)); let content = crate::json::to_vec_pretty_sorted(&meta) .context("Failed to serialize meta")?; self.suppress_path(&meta_path); @@ -2005,8 +2001,7 @@ impl ApiService { indexmap::IndexMap::new(), indexmap::IndexMap::new(), ); - let meta_path = - parent_dir.join(format!("{}.meta.json5", encoded_name)); + let meta_path = parent_dir.join(format!("{}.meta.json5", encoded_name)); let content = crate::json::to_vec_pretty_sorted(&meta) .context("Failed to serialize meta")?; self.suppress_path(&meta_path); @@ -2061,8 +2056,7 @@ impl ApiService { // Recursively process children self.process_children_incremental(&unique_children, &dir_path, stats)?; } else { - let content = - self.serialize_instance_to_model_json(added, meta_name_field)?; + let content = self.serialize_instance_to_model_json(added, meta_name_field)?; // Use the detected file path if available (preserves .model.json // vs .model.json5), otherwise default to .model.json5 let file_path = match &existing_format { @@ -2210,8 +2204,12 @@ impl ApiService { self.filter_properties_for_meta(&added.class_name, &added.properties, None); // For non-Folder classes, we need to include className - let meta = - self.build_meta_object(Some(&added.class_name), instance_name, properties, attributes); + let meta = self.build_meta_object( + Some(&added.class_name), + instance_name, + properties, + attributes, + ); let meta_path = dir_path.join("init.meta.json5"); let content = crate::json::to_vec_pretty_sorted(&meta) .context("Failed to serialize init.meta.json5")?;