rspack_binding_values 0.2.0

rspack binding values
use std::{ptr::NonNull, sync::Arc};

use napi::{Either, Env, JsString};
use napi_derive::napi;
use rspack_core::{Compilation, ModuleGraph, RuntimeSpec};
use rustc_hash::FxHashSet;

use crate::{JsDependency, JsModule, JsModuleWrapper};

#[napi]
pub struct JsModuleGraph {
  compilation: NonNull<Compilation>,
}

impl JsModuleGraph {
  pub fn new(compilation: &Compilation) -> Self {
    #[allow(clippy::unwrap_used)]
    JsModuleGraph {
      compilation: NonNull::new(compilation as *const Compilation as *mut Compilation).unwrap(),
    }
  }

  fn as_ref(&self) -> napi::Result<(&'static Compilation, ModuleGraph<'static>)> {
    let compilation = unsafe { self.compilation.as_ref() };
    let module_graph = compilation.get_module_graph();

    Ok((compilation, module_graph))
  }
}

#[napi]
impl JsModuleGraph {
  #[napi(ts_return_type = "JsModule | null")]
  pub fn get_module(&self, js_dependency: &JsDependency) -> napi::Result<Option<JsModuleWrapper>> {
    let (compilation, module_graph) = self.as_ref()?;
    let module = module_graph.get_module_by_dependency_id(&js_dependency.dependency_id);
    let js_module = module
      .map(|module| JsModuleWrapper::new(module.as_ref(), compilation.id(), Some(compilation)));
    Ok(js_module)
  }

  #[napi]
  pub fn get_used_exports(
    &self,
    env: Env,
    js_module: &JsModule,
    js_runtime: Either<String, Vec<String>>,
  ) -> napi::Result<Option<Either<bool, Vec<JsString>>>> {
    let (_, module_graph) = self.as_ref()?;

    let mut runtime: FxHashSet<Arc<str>> = FxHashSet::default();
    match js_runtime {
      Either::A(s) => {
        runtime.insert(Arc::from(s));
      }
      Either::B(vec) => {
        runtime.extend(vec.into_iter().map(Arc::from));
      }
    };
    let used_exports =
      module_graph.get_used_exports(&js_module.identifier, Some(&RuntimeSpec::new(runtime)));
    Ok(match used_exports {
      rspack_core::UsedExports::Null => None,
      rspack_core::UsedExports::Bool(b) => Some(Either::A(b)),
      rspack_core::UsedExports::Vec(vec) => Some(Either::B(
        vec
          .into_iter()
          .map(|atom| env.create_string(atom.as_str()))
          .collect::<napi::Result<Vec<_>>>()?,
      )),
    })
  }

  #[napi(ts_return_type = "JsModule | null")]
  pub fn get_issuer(&self, module: &JsModule) -> napi::Result<Option<JsModuleWrapper>> {
    let (compilation, module_graph) = self.as_ref()?;
    let issuer = module_graph.get_issuer(&module.identifier);
    Ok(
      issuer
        .map(|module| JsModuleWrapper::new(module.as_ref(), compilation.id(), Some(compilation))),
    )
  }
}