rspack_plugin_mf 0.100.1

rspack module federation plugin
Documentation
use std::{
  path::{Path, PathBuf},
  sync::Arc,
};

use camino::{Utf8Path, Utf8PathBuf};
use rspack_fs::ReadableFileSystem;
use rustc_hash::FxHashSet;

pub mod collect_shared_entry_plugin;
pub mod consume_shared_fallback_dependency;
pub mod consume_shared_module;
pub mod consume_shared_plugin;
pub mod consume_shared_runtime_module;
pub mod provide_for_shared_dependency;
pub mod provide_shared_dependency;
pub mod provide_shared_module;
pub mod provide_shared_module_factory;
pub mod provide_shared_plugin;
pub mod share_runtime_module;
pub mod share_runtime_plugin;
pub mod shared_container_plugin;
pub mod shared_container_runtime_module;
pub mod shared_used_exports_optimizer_plugin;
pub mod shared_used_exports_optimizer_runtime_module;

const DESCRIPTION_FILE_NAME: &str = "package.json";

fn is_node_modules_dir(dir: &Path) -> bool {
  dir.file_name().is_some_and(|name| name == "node_modules")
}

fn collect_description_file_paths(mut dir: &Path) -> Vec<PathBuf> {
  let mut description_file_paths = Vec::new();

  loop {
    if is_node_modules_dir(dir) {
      break;
    }

    description_file_paths.push(dir.join(DESCRIPTION_FILE_NAME));

    if let Some(parent) = dir.parent() {
      dir = parent;
    } else {
      break;
    }
  }

  description_file_paths
}

fn find_ancestor_description_data<T>(
  start_dir: &Path,
  mut matcher: impl FnMut(&Path, &serde_json::Value) -> Option<T>,
) -> Option<T> {
  for description_file in collect_description_file_paths(start_dir) {
    if let Ok(data) = std::fs::read(&description_file)
      && let Ok(data) = serde_json::from_slice::<serde_json::Value>(&data)
      && let Some(dir) = description_file.parent()
      && let Some(value) = matcher(dir, &data)
    {
      return Some(value);
    }
  }

  None
}

async fn get_description_file(
  fs: Arc<dyn ReadableFileSystem>,
  dir: &Utf8Path,
  satisfies_description_file_data: Option<impl Fn(&serde_json::Value) -> bool>,
) -> (Option<serde_json::Value>, Option<Vec<String>>) {
  let mut checked_file_paths = FxHashSet::default();

  for description_file in collect_description_file_paths(dir.as_std_path()) {
    let description_file = Utf8PathBuf::from_path_buf(description_file)
      .expect("description file path should remain utf8");
    let data = fs.read(&description_file).await;

    if let Ok(data) = data
      && let Ok(data) = serde_json::from_slice::<serde_json::Value>(&data)
    {
      if satisfies_description_file_data
        .as_ref()
        .is_some_and(|f| !f(&data))
      {
        checked_file_paths.insert(description_file.to_string());
      } else {
        return (Some(data), None);
      }
    }
  }

  let mut checked_file_paths = checked_file_paths.into_iter().collect::<Vec<_>>();
  checked_file_paths.sort_unstable();

  (None, Some(checked_file_paths))
}