use std::{
collections::HashMap,
ffi::{CString, c_char, c_void},
};
use typescript_types::{TsError, TsValue};
use crate::platform::dylib::{DynamicLibrary, Symbol};
pub struct NapiModuleLoader {
modules: HashMap<String, LoadedNapiModule>,
}
pub struct LoadedNapiModule {
pub name: String,
pub path: String,
library: DynamicLibrary,
pub exports: HashMap<String, NapiExport>,
}
#[derive(Clone)]
pub enum NapiExport {
Function(NapiFunction),
Value(TsValue),
}
#[derive(Clone)]
pub struct NapiFunction {
pub name: String,
func_ptr: *const c_void,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum NapiValueType {
Undefined = 0,
Null = 1,
Boolean = 2,
Number = 3,
String = 4,
Symbol = 5,
Object = 6,
Function = 7,
External = 8,
Bigint = 9,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct NapiValue(*mut c_void);
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct NapiEnv(*mut c_void);
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum NapiStatus {
Ok = 0,
InvalidArg = 1,
ObjectExpected = 2,
StringExpected = 3,
NameExpected = 4,
FunctionExpected = 5,
NumberExpected = 6,
BooleanExpected = 7,
ArrayExpected = 8,
GenericFailure = 9,
PendingException = 10,
Cancelled = 11,
EscapeCalledTwice = 12,
HandleScopeMismatch = 13,
CallbackScopeMismatch = 14,
QueueFull = 15,
Closing = 16,
BigintExpected = 17,
DateExpected = 18,
ArraybufferExpected = 19,
DetachableArraybufferExpected = 20,
WouldDeadlock = 21,
NoExternalBuffersAllowed = 22,
}
#[repr(C)]
pub struct NapiModule {
pub nm_version: i32,
pub nm_flags: u32,
pub nm_filename: *const c_char,
pub nm_register_func: Option<extern "C" fn(env: NapiEnv, exports: NapiValue) -> NapiValue>,
pub nm_modname: *const c_char,
pub nm_priv: *mut c_void,
pub reserved: [*mut c_void; 4],
}
impl NapiModuleLoader {
pub fn new() -> Self {
Self { modules: HashMap::new() }
}
pub fn load_module(&mut self, name: &str, path: &str) -> Result<&LoadedNapiModule, TsError> {
if self.modules.contains_key(name) {
return self.modules.get(name).ok_or_else(|| TsError::ReferenceError(format!("Module '{}' not found", name)));
}
let library =
DynamicLibrary::open(path).map_err(|e| TsError::Other(format!("Failed to load module '{}': {}", name, e)))?;
let napi_module_ptr: Symbol<*const NapiModule> =
library.get("napi_module").map_err(|e| TsError::Other(format!("Failed to find napi_module symbol: {}", e)))?;
let napi_module = unsafe { &**napi_module_ptr };
let env = NapiEnv(std::ptr::null_mut());
let exports = if let Some(register_func) = napi_module.nm_register_func {
let exports = NapiValue(std::ptr::null_mut());
register_func(env, exports)
}
else {
NapiValue(std::ptr::null_mut())
};
let exports_map = self.parse_exports(env, exports)?;
let loaded_module = LoadedNapiModule { name: name.to_string(), path: path.to_string(), library, exports: exports_map };
self.modules.insert(name.to_string(), loaded_module);
self.modules.get(name).ok_or_else(|| TsError::ReferenceError(format!("Module '{}' not found", name)))
}
fn parse_exports(&self, _env: NapiEnv, _exports: NapiValue) -> Result<HashMap<String, NapiExport>, TsError> {
Ok(HashMap::new())
}
pub fn get_module(&self, name: &str) -> Option<&LoadedNapiModule> {
self.modules.get(name)
}
pub fn has_module(&self, name: &str) -> bool {
self.modules.contains_key(name)
}
pub fn unload_module(&mut self, name: &str) -> Result<(), TsError> {
self.modules.remove(name).ok_or_else(|| TsError::ReferenceError(format!("Module '{}' not loaded", name)))?;
Ok(())
}
pub fn module_names(&self) -> Vec<&String> {
self.modules.keys().collect()
}
pub fn clear(&mut self) {
self.modules.clear();
}
}
impl Default for NapiModuleLoader {
fn default() -> Self {
Self::new()
}
}
impl LoadedNapiModule {
pub fn get_function(&self, name: &str) -> Option<&NapiFunction> {
self.exports.get(name).and_then(|export| match export {
NapiExport::Function(func) => Some(func),
_ => None,
})
}
pub fn get_value(&self, name: &str) -> Option<&TsValue> {
self.exports.get(name).and_then(|export| match export {
NapiExport::Value(val) => Some(val),
_ => None,
})
}
pub fn has_export(&self, name: &str) -> bool {
self.exports.contains_key(name)
}
pub fn export_names(&self) -> Vec<&String> {
self.exports.keys().collect()
}
}
impl NapiFunction {
pub fn new(name: &str, func_ptr: *const c_void) -> Self {
Self { name: name.to_string(), func_ptr }
}
pub fn call(&self, args: &[TsValue]) -> Result<TsValue, TsError> {
let _ = args;
let _ = self.func_ptr;
Ok(TsValue::Undefined)
}
}
pub fn ts_value_to_napi(_env: NapiEnv, value: &TsValue) -> Result<NapiValue, TsError> {
match value {
TsValue::Undefined => Ok(NapiValue(std::ptr::null_mut())),
TsValue::Null => Ok(NapiValue(std::ptr::null_mut())),
TsValue::Boolean(_b) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Number(_n) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::String(_s) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Object(_props) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Array(_arr) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Function(_f) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::BigInt(_bi) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Error(s) => Err(TsError::Other(s.clone())),
TsValue::Union(values) => {
if values.is_empty() {
Ok(NapiValue(std::ptr::null_mut()))
}
else {
ts_value_to_napi(_env, &values[0])
}
}
TsValue::Generic(_name, _args) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Symbol(_s) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Date(_timestamp) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::RegExp(_pattern) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Map(_entries) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Set(_values) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Promise(_value) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Iterable(_iter) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Conditional(_) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Mapped(_) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::TemplateLiteral(_) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::KeyOf(_) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::TypeOf(_) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::IndexedAccess { .. } => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Tuple(_) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Readonly(_) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Nullable(_) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::NonNullable(_) => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Infer { .. } => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::FunctionType { .. } => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::ConstructorType { .. } => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::ThisType => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Never => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Unknown => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Any => {
Ok(NapiValue(std::ptr::null_mut()))
}
TsValue::Void => {
Ok(NapiValue(std::ptr::null_mut()))
}
}
}
pub fn napi_to_ts_value(_env: NapiEnv, _value: NapiValue) -> Result<TsValue, TsError> {
Ok(TsValue::Undefined)
}
pub fn create_napi_error(message: &str) -> TsError {
TsError::Other(format!("NAPI Error: {}", message))
}
pub fn check_napi_status(status: NapiStatus) -> Result<(), TsError> {
if status == NapiStatus::Ok {
Ok(())
}
else {
Err(TsError::Other(format!("NAPI operation failed with status: {:?}", status)))
}
}