rspack_binding_api 0.100.7

Rspack shared binding API
Documentation
use napi::{
  CallContext, Either, JsObject, NapiRaw,
  bindgen_prelude::{FromNapiMutRef, Object, ToNapiValue},
};
use rspack_core::{ResourceData, ResourceParsedData, parse_resource};

use crate::{
  impl_module_methods,
  module::{MODULE_PROPERTIES_BUFFER, Module},
  plugins::JsLoaderItem,
  resource_data::ReadonlyResourceDataWrapper,
};

#[napi]
#[repr(C)]
pub struct NormalModule {
  pub(crate) module: Module,
}

impl NormalModule {
  pub fn new(module: Module) -> Self {
    Self { module }
  }

  pub(crate) fn custom_into_instance(
    mut self,
    env: &napi::Env,
  ) -> napi::Result<napi::bindgen_prelude::ClassInstance<'_, Self>> {
    let (_, module) = self.as_ref()?;

    let resource_resolved_data = module.resource_resolved_data();
    let resource = env.create_string(resource_resolved_data.resource())?;
    let request = env.create_string(module.request())?;
    let user_request = env.create_string(module.user_request())?;
    let raw_request = env.create_string(module.raw_request())?;
    let resource_resolve_data = Object::from_raw(env.raw(), unsafe {
      ToNapiValue::to_napi_value(
        env.raw(),
        ReadonlyResourceDataWrapper::from(resource_resolved_data.clone()),
      )?
    });
    let loaders = Object::from_raw(env.raw(), unsafe {
      ToNapiValue::to_napi_value(
        env.raw(),
        module
          .loaders()
          .iter()
          .map(JsLoaderItem::from)
          .collect::<Vec<_>>(),
      )?
    });

    #[js_function]
    pub fn match_resource_getter(ctx: CallContext<'_>) -> napi::Result<Either<&str, ()>> {
      let this = ctx.this_unchecked::<JsObject>();
      let env = ctx.env.raw();
      let wrapped_value = unsafe { NormalModule::from_napi_mut_ref(env, this.raw())? };

      let (_, module) = wrapped_value.as_ref()?;
      Ok(match module.match_resource() {
        Some(match_resource) => Either::A(match_resource.resource()),
        None => Either::B(()),
      })
    }

    #[js_function(1)]
    pub fn match_resource_setter(ctx: CallContext) -> napi::Result<()> {
      let this = ctx.this_unchecked::<JsObject>();
      let env = ctx.env.raw();
      let wrapped_value = unsafe { NormalModule::from_napi_mut_ref(env, this.raw())? };

      let val = ctx.get::<Either<String, ()>>(0)?;
      match val {
        Either::A(val) => {
          let module = wrapped_value.as_mut()?;
          let ResourceParsedData {
            path,
            query,
            fragment,
          } = parse_resource(&val).expect("Should parse resource");
          *module.match_resource_mut() =
            Some(ResourceData::new_with_path(val, path, query, fragment));
        }
        Either::B(_) => {}
      }
      Ok(())
    }

    MODULE_PROPERTIES_BUFFER.with(|ref_cell| {
      let mut properties = ref_cell.borrow_mut();
      properties.clear();

      properties.push(
        napi::Property::new()
          .with_utf8_name("resource")?
          .with_value(&resource),
      );
      properties.push(
        napi::Property::new()
          .with_utf8_name("request")?
          .with_value(&request),
      );
      properties.push(
        napi::Property::new()
          .with_utf8_name("userRequest")?
          .with_value(&user_request),
      );
      properties.push(
        napi::Property::new()
          .with_utf8_name("rawRequest")?
          .with_value(&raw_request),
      );
      properties.push(
        napi::Property::new()
          .with_utf8_name("resourceResolveData")?
          .with_value(&resource_resolve_data),
      );
      properties.push(
        napi::Property::new()
          .with_utf8_name("loaders")?
          .with_value(&loaders),
      );
      properties.push(
        napi::Property::new()
          .with_utf8_name("matchResource")?
          .with_getter(match_resource_getter)
          .with_setter(match_resource_setter),
      );
      Self::new_inherited(self, env, &mut properties)
    })
  }

  fn as_ref(&mut self) -> napi::Result<(&rspack_core::Compilation, &rspack_core::NormalModule)> {
    let (compilation, module) = self.module.as_ref()?;
    match module.as_normal_module() {
      Some(normal_module) => Ok((compilation, normal_module)),
      None => Err(napi::Error::new(
        napi::Status::GenericFailure,
        "Module is not a NormalModule",
      )),
    }
  }

  fn as_mut(&mut self) -> napi::Result<&mut rspack_core::NormalModule> {
    let module = self.module.as_mut()?;
    match module.as_normal_module_mut() {
      Some(normal_module) => Ok(normal_module),
      None => Err(napi::Error::new(
        napi::Status::GenericFailure,
        "Module is not a NormalModule",
      )),
    }
  }
}

impl_module_methods!(NormalModule);