diff --git a/packages/nx/src/native/watch/types.rs b/packages/nx/src/native/watch/types.rs index 2ba55065f23ce4..433378d2b70794 100644 --- a/packages/nx/src/native/watch/types.rs +++ b/packages/nx/src/native/watch/types.rs @@ -24,11 +24,11 @@ pub struct WatchEvent { pub r#type: EventType, } -impl From for WatchEvent { - fn from(value: WatchEventInternal) -> Self { +impl From<&WatchEventInternal> for WatchEvent { + fn from(value: &WatchEventInternal) -> Self { let path = value .path - .strip_prefix(&value.origin.expect("origin is available")) + .strip_prefix(value.origin.as_ref().expect("origin is available")) .unwrap_or(&value.path) .display() .to_string(); diff --git a/packages/nx/src/native/watch/watcher.rs b/packages/nx/src/native/watch/watcher.rs index 99c02df84b8ad0..86616842cb60c0 100644 --- a/packages/nx/src/native/watch/watcher.rs +++ b/packages/nx/src/native/watch/watcher.rs @@ -1,9 +1,10 @@ +use std::collections::hash_map::Entry; use std::collections::HashMap; use std::convert::Infallible; use std::path::MAIN_SEPARATOR; use std::sync::Arc; -use crate::native::watch::types::{WatchEvent, WatchEventInternal}; +use crate::native::watch::types::{EventType, WatchEvent, WatchEventInternal}; use itertools::Itertools; use napi::bindgen_prelude::*; use napi::threadsafe_function::{ @@ -68,27 +69,22 @@ impl Watcher { .with_env_filter(EnvFilter::from_env("NX_NATIVE_LOGGING")) .try_init(); - let mut callback_tsfn: ThreadsafeFunction>> = - callback.create_threadsafe_function( - 0, - |ctx: ThreadSafeCallContext>>| { - let mut watch_events: Vec = vec![]; - trace!(?ctx.value, "Base collection that will be sent"); + let mut callback_tsfn: ThreadsafeFunction> = callback + .create_threadsafe_function( + 0, + |ctx: ThreadSafeCallContext>| { + let mut watch_events: Vec = vec![]; + trace!(?ctx.value, "Base collection that will be sent"); - for (_, value) in ctx.value { - let event = value - .first() - .expect("should always have at least 1 element") - .to_owned(); - - watch_events.push(event.into()); - } + for event in ctx.value.values() { + watch_events.push(event.into()); + } - trace!(?watch_events, "sending to node"); + trace!(?watch_events, "sending to node"); - Ok(vec![watch_events]) - }, - )?; + Ok(vec![watch_events]) + }, + )?; callback_tsfn.unref(&env)?; @@ -150,10 +146,30 @@ impl Watcher { }) .collect::>(); - let group_events = events - .into_iter() - .into_group_map_by(|g| g.path.display().to_string()); - + let mut group_events: HashMap = HashMap::new(); + for g in events.into_iter() { + let path = g.path.display().to_string(); + + // Delete > Create > Modify + match group_events.entry(path) { + // Delete should override anything + Entry::Occupied(mut e) if matches!(g.r#type, EventType::delete) => { + e.insert(g); + } + // Create should override update + Entry::Occupied(mut e) + if matches!(g.r#type, EventType::create) + && matches!(e.get().r#type, EventType::update) => + { + e.insert(g); + } + Entry::Occupied(_) => {} + // If its empty, insert + Entry::Vacant(e) => { + e.insert(g); + } + } + } callback_tsfn.call(Ok(group_events), ThreadsafeFunctionCallMode::NonBlocking); action.outcome(Outcome::Start);