rspack_plugin_javascript 0.100.5

rspack javascript plugin
Documentation
mod esm_compatibility_dependency;
mod esm_export_expression_dependency;
mod esm_export_header_dependency;
mod esm_export_imported_specifier_dependency;
mod esm_export_specifier_dependency;
mod esm_import_dependency;
mod esm_import_specifier_dependency;
mod external_module_dependency;
mod import_dependency;
mod import_eager_dependency;
mod import_meta_resolve_dependency;
mod import_meta_resolve_header_dependency;
mod import_meta_rsc_dependency;
mod import_weak_dependency;
mod provide_dependency;

use std::fmt::Write as _;

use rspack_core::{DependencyCategory, ImportAttributes, ResourceIdentifier};

pub use self::{
  esm_compatibility_dependency::{ESMCompatibilityDependency, ESMCompatibilityDependencyTemplate},
  esm_export_expression_dependency::{
    DeclarationId, DeclarationInfo, ESMExportExpressionDependency,
    ESMExportExpressionDependencyTemplate,
  },
  esm_export_header_dependency::{ESMExportHeaderDependency, ESMExportHeaderDependencyTemplate},
  esm_export_imported_specifier_dependency::{
    ESMExportImportedSpecifierDependency, ESMExportImportedSpecifierDependencyTemplate,
  },
  esm_export_specifier_dependency::{
    ESMExportSpecifierDependency, ESMExportSpecifierDependencyTemplate,
  },
  esm_import_dependency::{
    ESMImportSideEffectDependency, ESMImportSideEffectDependencyTemplate,
    esm_import_dependency_apply, import_emitted_runtime,
  },
  esm_import_specifier_dependency::{
    ESMImportSpecifierDependency, ESMImportSpecifierDependencyTemplate,
  },
  external_module_dependency::{ExternalModuleDependency, ExternalModuleDependencyTemplate},
  import_dependency::{ImportDependency, ImportDependencyTemplate},
  import_eager_dependency::{ImportEagerDependency, ImportEagerDependencyTemplate},
  import_meta_resolve_dependency::{
    ImportMetaResolveDependency, ImportMetaResolveDependencyTemplate,
  },
  import_meta_resolve_header_dependency::{
    ImportMetaResolveHeaderDependency, ImportMetaResolveHeaderDependencyTemplate,
  },
  import_meta_rsc_dependency::{
    IMPORT_META_RSC_BINDING, ImportMetaRscDependency, ImportMetaRscDependencyTemplate,
  },
  import_weak_dependency::{ImportWeakDependency, ImportWeakDependencyTemplate},
  provide_dependency::{ProvideDependency, ProvideDependencyTemplate},
};

pub fn create_resource_identifier_for_esm_dependency(
  request: &str,
  attributes: Option<&ImportAttributes>,
) -> ResourceIdentifier {
  let category = DependencyCategory::Esm.as_str();
  let mut ident = String::with_capacity(category.len() + 1 + request.len());
  ident.push_str(category);
  ident.push('|');
  ident.push_str(request);

  let Some(attributes) = attributes else {
    return ident.into();
  };
  let mut iter = attributes.iter();
  let Some(first) = iter.next() else {
    ident.push_str("|attrs=0");
    return ident.into();
  };
  let Some(second) = iter.next() else {
    push_esm_resource_identifier_attributes(&mut ident, std::iter::once(first), 1);
    return ident.into();
  };

  let mut attrs = Vec::with_capacity(iter.size_hint().0 + 2);
  attrs.push(first);
  attrs.push(second);
  attrs.extend(iter);
  attrs.sort_unstable_by(|a, b| a.0.cmp(b.0));
  let len = attrs.len();
  push_esm_resource_identifier_attributes(&mut ident, attrs.into_iter(), len);
  ident.into()
}

fn push_esm_resource_identifier_attributes<'a>(
  ident: &mut String,
  attrs: impl Iterator<Item = (&'a str, &'a str)>,
  len: usize,
) {
  ident.push_str("|attrs=");
  write!(ident, "{len}").expect("write to String should not fail");

  for (key, value) in attrs {
    ident.reserve(key.len() + value.len() + 8);
    push_esm_resource_identifier_attribute_part(ident, key);
    push_esm_resource_identifier_attribute_part(ident, value);
  }
}

fn push_esm_resource_identifier_attribute_part(ident: &mut String, value: &str) {
  ident.push('|');
  write!(ident, "{}:", value.len()).expect("write to String should not fail");
  ident.push_str(value);
}

#[cfg(test)]
mod tests {
  use rspack_core::ImportAttributes;

  use super::create_resource_identifier_for_esm_dependency;

  #[test]
  fn creates_resource_identifier_with_sorted_import_attributes() {
    let attributes = ImportAttributes::from_iter([
      ("type".to_string(), "json".to_string()),
      ("integrity".to_string(), "sha256".to_string()),
    ]);

    let ident = create_resource_identifier_for_esm_dependency("./data.json", Some(&attributes));

    assert_eq!(
      ident.to_string(),
      "esm|./data.json|attrs=2|9:integrity|6:sha256|4:type|4:json"
    );
  }

  #[test]
  fn creates_resource_identifier_without_attribute_delimiter_collisions() {
    let first_attributes = ImportAttributes::from_iter([("a".to_string(), "b|c=d".to_string())]);
    let second_attributes = ImportAttributes::from_iter([
      ("a".to_string(), "b".to_string()),
      ("c".to_string(), "d".to_string()),
    ]);

    let first =
      create_resource_identifier_for_esm_dependency("./data.json", Some(&first_attributes));
    let second =
      create_resource_identifier_for_esm_dependency("./data.json", Some(&second_attributes));

    assert_ne!(first, second);
  }
}