From c3b047df4592d252ab26339de30901d56fe6b1b3 Mon Sep 17 00:00:00 2001 From: shulaoda Date: Tue, 29 Oct 2024 22:56:49 +0800 Subject: [PATCH] refactor(rspack_napi): simplify the logic of JsRegExp --- .../rspack_napi/src/js_values/js_reg_exp.rs | 51 ++++++++++--------- crates/rspack_napi/src/utils.rs | 47 +---------------- 2 files changed, 27 insertions(+), 71 deletions(-) diff --git a/crates/rspack_napi/src/js_values/js_reg_exp.rs b/crates/rspack_napi/src/js_values/js_reg_exp.rs index 5e66b5ca8722..e6c0061e9b6a 100644 --- a/crates/rspack_napi/src/js_values/js_reg_exp.rs +++ b/crates/rspack_napi/src/js_values/js_reg_exp.rs @@ -1,12 +1,10 @@ use std::fmt::Debug; use napi::{ - bindgen_prelude::{FromNapiValue, TypeName, ValidateNapiValue}, - sys, Error, JsObject, NapiRaw, NapiValue, Result, Status, + bindgen_prelude::{FromNapiValue, Function, TypeName, ValidateNapiValue}, + sys, Env, Error, JsObject, JsUnknown, NapiRaw, NapiValue, Result, Status, }; -use crate::utils::NapiTypeRef; - pub struct JsRegExp(JsObject); impl Debug for JsRegExp { @@ -31,6 +29,18 @@ impl JsRegExp { } } +impl ValidateNapiValue for JsRegExp {} + +impl TypeName for JsRegExp { + fn type_name() -> &'static str { + "RegExp" + } + + fn value_type() -> napi::ValueType { + napi::ValueType::Object + } +} + impl NapiRaw for JsRegExp { unsafe fn raw(&self) -> sys::napi_value { unsafe { self.0.raw() } @@ -39,31 +49,22 @@ impl NapiRaw for JsRegExp { impl FromNapiValue for JsRegExp { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result { - // Safety: `JsObject::call_without_args` only leverages the `JsObject::raw` method. - // It's not necessarily have to be exactly an `JsObject` instance. let js_object = unsafe { JsObject::from_raw_unchecked(env, napi_val) }; - let ty = unsafe { NapiTypeRef::new(env, &js_object) }?; - if !ty.is_regex()? { - return Err(Error::new( - Status::InvalidArg, + + let env = Env::from(env); + let global = env.get_global()?; + let regexp_constructor = global.get_named_property::>("RegExp")?; + + if js_object.instanceof(regexp_constructor)? { + Ok(Self(js_object)) + } else { + Err(Error::new( + Status::ObjectExpected, format!( "Expect value to be '[object RegExp]', but received {}", - ty.get_type()? + js_object.coerce_to_string()?.into_utf8()?.as_str()? ), - )); + )) } - Ok(Self(unsafe { JsObject::from_napi_value(env, napi_val) }?)) - } -} - -impl ValidateNapiValue for JsRegExp {} - -impl TypeName for JsRegExp { - fn type_name() -> &'static str { - "RegExp" - } - - fn value_type() -> napi::ValueType { - napi::ValueType::Object } } diff --git a/crates/rspack_napi/src/utils.rs b/crates/rspack_napi/src/utils.rs index c4180d7d3550..866d534c5f24 100644 --- a/crates/rspack_napi/src/utils.rs +++ b/crates/rspack_napi/src/utils.rs @@ -1,49 +1,4 @@ -use std::marker::PhantomData; - -use napi::{ - bindgen_prelude::FromNapiValue, sys, Env, JsFunction, JsObject, JsString, JsStringUtf8, - JsUnknown, NapiRaw, NapiValue, Result, -}; - -/// `Object.prototype.toString.call` -/// Safety: [napi::JsStringUtf8]'s lifetime is bound to `&T` -unsafe fn object_prototype_to_string_call( - raw_env: sys::napi_env, - obj: &T, -) -> Result { - let env = Env::from(raw_env); - let s: JsString = env - .get_global()? - // `Object` is a function, but we want to use it as an JSObject. - .get_named_property_unchecked::("Object")? - .get_named_property::("prototype")? - .get_named_property::("toString")? - .call_without_args(Some( - // Safety: `JsObject::call_without_args` only leverages the `JsObject::raw` method. - // It's not necessarily have to be exactly an `JsObject` instance. - unsafe { &JsObject::from_raw_unchecked(raw_env, obj.raw()) }, - ))? - .try_into()?; - s.into_utf8() -} - -pub struct NapiTypeRef<'r>(JsStringUtf8, PhantomData<&'r *mut ()>); - -impl<'r> NapiTypeRef<'r> { - // Safety: This call would be successful when `val` is a valid `impl NapiRaw` and `env` is a valid `napi_env`. - pub unsafe fn new(env: sys::napi_env, val: &'r T) -> Result> { - let s = unsafe { object_prototype_to_string_call(env, val) }?; - Ok(Self(s, PhantomData)) - } - - pub fn get_type(&self) -> Result<&str> { - self.0.as_str() - } - - pub fn is_regex(&self) -> Result { - Ok(self.get_type()? == "[object RegExp]") - } -} +use napi::{bindgen_prelude::FromNapiValue, JsUnknown}; pub fn downcast_into(o: JsUnknown) -> napi::Result { ::from_unknown(o)