From ea3fff25aeaaaaa936949c66a8bfcb7cc83f09b8 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Wed, 26 Aug 2020 00:07:27 +0800 Subject: [PATCH 1/2] feat(napi): serde-json feature --- napi/Cargo.toml | 8 + napi/src/env.rs | 41 +- napi/src/error.rs | 25 +- napi/src/js_values/arraybuffer.rs | 12 +- napi/src/js_values/bigint.rs | 195 +++++++- napi/src/js_values/buffer.rs | 13 +- napi/src/js_values/de.rs | 358 ++++++++++++++ napi/src/js_values/mod.rs | 22 +- napi/src/js_values/object.rs | 45 +- napi/src/js_values/ser.rs | 510 ++++++++++++++++++++ napi/src/js_values/string.rs | 24 + napi/src/js_values/value.rs | 2 +- napi/src/lib.rs | 4 + napi/src/threadsafe_function.rs | 67 ++- test_module/Cargo.toml | 6 +- test_module/__test__/napi-version.ts | 3 +- test_module/__test__/serde/de.spec.ts | 39 ++ test_module/__test__/serde/ser.spec.ts | 26 + test_module/__test__/serde/ser.spec.ts.md | 130 +++++ test_module/__test__/serde/ser.spec.ts.snap | Bin 0 -> 1038 bytes test_module/src/lib.rs | 22 +- test_module/src/napi4/tsfn.rs | 39 +- test_module/src/napi6/bigint.rs | 16 +- test_module/src/serde.rs | 182 +++++++ 24 files changed, 1672 insertions(+), 117 deletions(-) create mode 100644 napi/src/js_values/de.rs create mode 100644 napi/src/js_values/ser.rs create mode 100644 test_module/__test__/serde/de.spec.ts create mode 100644 test_module/__test__/serde/ser.spec.ts create mode 100644 test_module/__test__/serde/ser.spec.ts.md create mode 100644 test_module/__test__/serde/ser.spec.ts.snap create mode 100644 test_module/src/serde.rs diff --git a/napi/Cargo.toml b/napi/Cargo.toml index e68e90d0..34a6da47 100644 --- a/napi/Cargo.toml +++ b/napi/Cargo.toml @@ -12,6 +12,7 @@ edition = "2018" [features] libuv = ["futures"] tokio_rt = ["futures", "tokio", "once_cell"] +serde-json = ["serde", "serde_json"] [dependencies] napi-sys = { version = "0.4", path = "../sys" } @@ -29,6 +30,13 @@ optional = true version = "1.4" optional = true +[dependencies.serde] +version = "1" +optional = true + +[dependencies.serde_json] +version = "1" +optional = true [build-dependencies] napi-build = { version = "0.2", path = "../build" } diff --git a/napi/src/env.rs b/napi/src/env.rs index 0c2c72a6..00b47968 100644 --- a/napi/src/env.rs +++ b/napi/src/env.rs @@ -11,12 +11,18 @@ use crate::js_values::*; use crate::task::Task; use crate::{sys, Error, NodeVersion, Result, Status}; +#[cfg(all(feature = "serde-json"))] +use crate::js_values::{De, Ser}; #[cfg(all(any(feature = "libuv", feature = "tokio_rt"), napi4))] use crate::promise; #[cfg(all(feature = "tokio_rt", napi4))] use crate::tokio_rt::{get_tokio_sender, Message}; #[cfg(all(feature = "libuv", napi4))] use crate::uv; +#[cfg(all(feature = "serde-json"))] +use serde::de::DeserializeOwned; +#[cfg(all(feature = "serde-json"))] +use serde::Serialize; #[cfg(all(feature = "libuv", napi4))] use std::future::Future; #[cfg(all(feature = "tokio_rt", napi4))] @@ -98,7 +104,7 @@ impl Env { pub fn create_bigint_from_i64(&self, value: i64) -> Result { let mut raw_value = ptr::null_mut(); check_status(unsafe { sys::napi_create_bigint_int64(self.0, value, &mut raw_value) })?; - Ok(JsBigint::from_raw_unchecked(self.0, raw_value)) + Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1)) } #[cfg(napi6)] @@ -107,7 +113,7 @@ impl Env { pub fn create_bigint_from_u64(&self, value: u64) -> Result { let mut raw_value = ptr::null_mut(); check_status(unsafe { sys::napi_create_bigint_uint64(self.0, value, &mut raw_value) })?; - Ok(JsBigint::from_raw_unchecked(self.0, raw_value)) + Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1)) } #[cfg(napi6)] @@ -116,6 +122,7 @@ impl Env { /// The resulting BigInt will be negative when sign_bit is true. pub fn create_bigint_from_words(&self, sign_bit: bool, words: Vec) -> Result { let mut raw_value = ptr::null_mut(); + let len = words.len(); check_status(unsafe { sys::napi_create_bigint_words( self.0, @@ -123,12 +130,12 @@ impl Env { true => 1, false => 0, }, - words.len() as u64, + len as u64, words.as_ptr(), &mut raw_value, ) })?; - Ok(JsBigint::from_raw_unchecked(self.0, raw_value)) + Ok(JsBigint::from_raw_unchecked(self.0, raw_value, len as _)) } #[inline] @@ -608,6 +615,32 @@ impl Env { Ok(JsObject::from_raw_unchecked(self.0, raw_promise)) } + #[cfg(feature = "serde-json")] + #[inline] + pub fn to_js_value(&self, node: &T) -> Result + where + T: Serialize, + { + let s = Ser(self); + node.serialize(s).map(JsUnknown) + } + + #[cfg(feature = "serde-json")] + #[inline] + pub fn from_js_value(&self, value: V) -> Result + where + T: DeserializeOwned + ?Sized, + V: NapiValue, + { + let value = Value { + env: self.0, + value: value.raw_value(), + value_type: ValueType::Unknown, + }; + let mut de = De(&value); + T::deserialize(&mut de) + } + #[inline] pub fn strict_equals(&self, a: A, b: B) -> Result { let mut result = false; diff --git a/napi/src/error.rs b/napi/src/error.rs index 6c44603d..a515c5e6 100644 --- a/napi/src/error.rs +++ b/napi/src/error.rs @@ -1,7 +1,14 @@ +use std::convert::From; +use std::error::Error as StdError; use std::fmt; +#[cfg(feature = "serde-json")] +use std::fmt::Display; use std::os::raw::c_char; use std::ptr; +#[cfg(feature = "serde-json")] +use serde::{de, ser}; + use crate::{sys, Status}; pub type Result = std::result::Result; @@ -12,6 +19,22 @@ pub struct Error { pub reason: String, } +impl StdError for Error {} + +#[cfg(feature = "serde-json")] +impl ser::Error for Error { + fn custom(msg: T) -> Self { + Error::new(Status::InvalidArg, msg.to_string()) + } +} + +#[cfg(feature = "serde-json")] +impl de::Error for Error { + fn custom(msg: T) -> Self { + Error::new(Status::InvalidArg, msg.to_string()) + } +} + impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}: {}", self.status, self.reason) @@ -82,6 +105,6 @@ pub fn check_status(code: sys::napi_status) -> Result<()> { let status = Status::from(code); match status { Status::Ok => Ok(()), - _ => Err(Error::from_status(status)), + _ => Err(Error::new(status, "".to_owned())), } } diff --git a/napi/src/js_values/arraybuffer.rs b/napi/src/js_values/arraybuffer.rs index a058c824..d156f6ab 100644 --- a/napi/src/js_values/arraybuffer.rs +++ b/napi/src/js_values/arraybuffer.rs @@ -1,8 +1,9 @@ +use std::convert::TryFrom; use std::ptr; -use super::{JsObject, NapiValue, Value, ValueType}; +use super::{JsObject, JsUnknown, NapiValue, Value, ValueType}; use crate::error::check_status; -use crate::{sys, Result}; +use crate::{sys, Error, Result}; #[derive(Debug)] pub struct JsArrayBuffer { @@ -46,3 +47,10 @@ impl NapiValue for JsArrayBuffer { }) } } + +impl TryFrom for JsArrayBuffer { + type Error = Error; + fn try_from(value: JsUnknown) -> Result { + JsArrayBuffer::from_raw(value.0.env, value.0.value) + } +} diff --git a/napi/src/js_values/bigint.rs b/napi/src/js_values/bigint.rs index 1001e709..5f583104 100644 --- a/napi/src/js_values/bigint.rs +++ b/napi/src/js_values/bigint.rs @@ -1,12 +1,146 @@ use std::convert::TryFrom; use std::ptr; -use super::{Error, Value}; +use super::*; use crate::error::check_status; use crate::{sys, Result}; #[derive(Debug)] -pub struct JsBigint(pub(crate) Value); +pub struct JsBigint { + pub(crate) raw: Value, + pub word_count: u64, +} + +impl JsBigint { + pub(crate) fn from_raw_unchecked( + env: sys::napi_env, + value: sys::napi_value, + word_count: u64, + ) -> Self { + Self { + raw: Value { + env, + value, + value_type: ValueType::Object, + }, + word_count, + } + } + + #[inline] + pub fn into_unknown(self) -> Result { + JsUnknown::from_raw(self.raw.env, self.raw.value) + } + + #[inline] + pub fn coerce_to_number(self) -> Result { + let mut new_raw_value = ptr::null_mut(); + let status = + unsafe { sys::napi_coerce_to_number(self.raw.env, self.raw.value, &mut new_raw_value) }; + check_status(status)?; + Ok(JsNumber(Value { + env: self.raw.env, + value: new_raw_value, + value_type: ValueType::Number, + })) + } + + #[inline] + pub fn coerce_to_string(self) -> Result { + let mut new_raw_value = ptr::null_mut(); + let status = + unsafe { sys::napi_coerce_to_string(self.raw.env, self.raw.value, &mut new_raw_value) }; + check_status(status)?; + Ok(JsString(Value { + env: self.raw.env, + value: new_raw_value, + value_type: ValueType::String, + })) + } + #[inline] + pub fn coerce_to_object(self) -> Result { + let mut new_raw_value = ptr::null_mut(); + let status = + unsafe { sys::napi_coerce_to_object(self.raw.env, self.raw.value, &mut new_raw_value) }; + check_status(status)?; + Ok(JsObject(Value { + env: self.raw.env, + value: new_raw_value, + value_type: ValueType::Object, + })) + } + + #[inline] + #[cfg(napi5)] + pub fn is_date(&self) -> Result { + let mut is_date = true; + let status = unsafe { sys::napi_is_date(self.raw.env, self.raw.value, &mut is_date) }; + check_status(status)?; + Ok(is_date) + } + + #[inline] + pub fn is_error(&self) -> Result { + let mut result = false; + check_status(unsafe { sys::napi_is_error(self.raw.env, self.raw.value, &mut result) })?; + Ok(result) + } + + #[inline] + pub fn is_typedarray(&self) -> Result { + let mut result = false; + check_status(unsafe { sys::napi_is_typedarray(self.raw.env, self.raw.value, &mut result) })?; + Ok(result) + } + + #[inline] + pub fn is_dataview(&self) -> Result { + let mut result = false; + check_status(unsafe { sys::napi_is_dataview(self.raw.env, self.raw.value, &mut result) })?; + Ok(result) + } + + #[inline] + pub fn instanceof(&self, constructor: Constructor) -> Result { + let mut result = false; + check_status(unsafe { + sys::napi_instanceof( + self.raw.env, + self.raw.value, + constructor.raw_value(), + &mut result, + ) + })?; + Ok(result) + } +} + +impl NapiValue for JsBigint { + fn raw_value(&self) -> sys::napi_value { + self.raw.value + } + + fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result { + let mut word_count: u64 = 0; + check_status(unsafe { + sys::napi_get_value_bigint_words( + env, + value, + ptr::null_mut(), + &mut word_count, + ptr::null_mut(), + ) + })?; + Ok(JsBigint { + raw: Value { + env, + value, + value_type: ValueType::Bigint, + }, + word_count, + }) + } +} /// The BigInt will be converted losslessly when the value is over what an int64 could hold. impl TryFrom for i64 { @@ -28,38 +162,26 @@ impl TryFrom for u64 { impl JsBigint { /// https://nodejs.org/api/n-api.html#n_api_napi_get_value_bigint_words - pub fn get_words(&self, sign_bit: bool) -> Result> { - let mut word_count: u64 = 0; + #[inline] + pub fn get_words(&mut self) -> Result<(bool, Vec)> { + let mut words: Vec = Vec::with_capacity(self.word_count as usize); + let word_count = &mut self.word_count; + let mut sign_bit = 0; check_status(unsafe { sys::napi_get_value_bigint_words( - self.0.env, - self.0.value, - ptr::null_mut(), - &mut word_count, - ptr::null_mut(), - ) - })?; - - let mut words: Vec = Vec::with_capacity(word_count as usize); - let mut sign_bit = match sign_bit { - true => 1, - false => 0, - }; - check_status(unsafe { - sys::napi_get_value_bigint_words( - self.0.env, - self.0.value, + self.raw.env, + self.raw.value, &mut sign_bit, - &mut word_count, + word_count, words.as_mut_ptr(), ) })?; unsafe { - words.set_len(word_count as usize); + words.set_len(self.word_count as usize); }; - Ok(words) + Ok((sign_bit == 1, words)) } #[inline] @@ -67,7 +189,7 @@ impl JsBigint { let mut val: u64 = 0; let mut loss = false; check_status(unsafe { - sys::napi_get_value_bigint_uint64(self.0.env, self.0.value, &mut val, &mut loss) + sys::napi_get_value_bigint_uint64(self.raw.env, self.raw.value, &mut val, &mut loss) })?; Ok((val, loss)) @@ -78,8 +200,29 @@ impl JsBigint { let mut val: i64 = 0; let mut loss: bool = false; check_status(unsafe { - sys::napi_get_value_bigint_int64(self.0.env, self.0.value, &mut val, &mut loss) + sys::napi_get_value_bigint_int64(self.raw.env, self.raw.value, &mut val, &mut loss) })?; Ok((val, loss)) } + + #[inline] + pub fn get_i128(&mut self) -> Result<(i128, bool)> { + let (signed, words) = self.get_words()?; + let len = words.len(); + let i128_words: [i64; 2] = [words[0] as _, words[1] as _]; + let mut val = unsafe { ptr::read(i128_words.as_ptr() as *const i128) }; + if signed { + val = -val; + } + Ok((val, len > 2)) + } + + #[inline] + pub fn get_u128(&mut self) -> Result<(bool, u128, bool)> { + let (signed, words) = self.get_words()?; + let len = words.len(); + let u128_words: [u64; 2] = [words[0], words[1]]; + let val = unsafe { ptr::read(u128_words.as_ptr() as *const u128) }; + Ok((signed, val, len > 2)) + } } diff --git a/napi/src/js_values/buffer.rs b/napi/src/js_values/buffer.rs index 8091ae5a..3b3dc9ac 100644 --- a/napi/src/js_values/buffer.rs +++ b/napi/src/js_values/buffer.rs @@ -1,10 +1,11 @@ +use std::convert::TryFrom; use std::ops::Deref; use std::ptr; use std::slice; use super::{JsObject, JsUnknown, NapiValue, Value, ValueType}; use crate::error::check_status; -use crate::{sys, Result}; +use crate::{sys, Error, Result}; #[derive(Debug)] pub struct JsBuffer { @@ -42,8 +43,7 @@ impl NapiValue for JsBuffer { fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result { let mut data = ptr::null_mut(); let mut len: u64 = 0; - let status = unsafe { sys::napi_get_buffer_info(env, value, &mut data, &mut len) }; - check_status(status)?; + check_status(unsafe { sys::napi_get_buffer_info(env, value, &mut data, &mut len) })?; Ok(JsBuffer { value: JsObject(Value { env, @@ -68,3 +68,10 @@ impl Deref for JsBuffer { self.data } } + +impl TryFrom for JsBuffer { + type Error = Error; + fn try_from(value: JsUnknown) -> Result { + JsBuffer::from_raw(value.0.env, value.0.value) + } +} diff --git a/napi/src/js_values/de.rs b/napi/src/js_values/de.rs new file mode 100644 index 00000000..2026926d --- /dev/null +++ b/napi/src/js_values/de.rs @@ -0,0 +1,358 @@ +use std::convert::TryInto; + +use serde::de::Visitor; +use serde::de::{DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Unexpected, VariantAccess}; + +use super::{type_of, NapiValue, Value, ValueType}; +#[cfg(napi6)] +use crate::JsBigint; +use crate::{Error, JsBoolean, JsBuffer, JsNumber, JsObject, JsString, JsUnknown, Result, Status}; + +pub(crate) struct De<'env>(pub(crate) &'env Value); + +#[doc(hidden)] +impl<'x, 'de, 'env> serde::de::Deserializer<'x> for &'de mut De<'env> { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'x>, + { + let js_value_type = type_of(self.0.env, self.0.value)?; + match js_value_type { + ValueType::Null | ValueType::Undefined => visitor.visit_unit(), + ValueType::Boolean => { + let js_boolean = JsBoolean::from_raw_unchecked(self.0.env, self.0.value); + visitor.visit_bool(js_boolean.get_value()?) + } + ValueType::Number => { + let js_number: f64 = JsNumber::from_raw_unchecked(self.0.env, self.0.value).try_into()?; + if js_number.trunc() == js_number { + visitor.visit_i64(js_number as i64) + } else { + visitor.visit_f64(js_number) + } + } + ValueType::String => { + let js_string = JsString::from_raw_unchecked(self.0.env, self.0.value); + visitor.visit_str(js_string.as_str()?) + } + ValueType::Object => { + let js_object = JsObject::from_raw_unchecked(self.0.env, self.0.value); + if js_object.is_array()? { + let mut deserializer = + JsArrayAccess::new(&js_object, js_object.get_array_length_unchecked()?); + visitor.visit_seq(&mut deserializer) + } else if js_object.is_buffer()? { + visitor.visit_bytes(JsBuffer::from_raw(self.0.env, self.0.value)?.data) + } else { + let mut deserializer = JsObjectAccess::new(&js_object)?; + visitor.visit_map(&mut deserializer) + } + } + #[cfg(napi6)] + ValueType::Bigint => { + let mut js_bigint = JsBigint::from_raw(self.0.env, self.0.value)?; + let (signed, v, _loss) = js_bigint.get_u128()?; + if signed { + visitor.visit_i128(-(v as i128)) + } else { + visitor.visit_u128(v) + } + } + ValueType::External | ValueType::Function | ValueType::Symbol => Err(Error::new( + Status::InvalidArg, + format!("typeof {:?} value could not be deserialized", js_value_type), + )), + ValueType::Unknown => unreachable!(), + } + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'x>, + { + visitor.visit_bytes(JsBuffer::from_raw(self.0.env, self.0.value)?.data) + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'x>, + { + visitor.visit_bytes(JsBuffer::from_raw(self.0.env, self.0.value)?.data) + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'x>, + { + match type_of(self.0.env, self.0.value)? { + ValueType::Undefined | ValueType::Null => visitor.visit_none(), + _ => visitor.visit_some(self), + } + } + + fn deserialize_enum( + self, + _name: &'static str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'x>, + { + let js_value_type = type_of(self.0.env, self.0.value)?; + match js_value_type { + ValueType::String => visitor.visit_enum(JsEnumAccess::new( + JsString::from_raw_unchecked(self.0.env, self.0.value) + .as_str()? + .to_owned(), + None, + )), + ValueType::Object => { + let js_object = JsObject::from_raw_unchecked(self.0.env, self.0.value); + let properties = js_object.get_property_names::()?; + let property_len = properties.get_array_length_unchecked()?; + if property_len != 1 { + Err(Error::new( + Status::InvalidArg, + format!( + "object key length: {}, can not deserialize to Enum", + property_len + ), + )) + } else { + let key = properties.get_index::(0)?; + let value: JsUnknown = js_object.get_property(&key)?; + visitor.visit_enum(JsEnumAccess::new(key.as_str()?.to_owned(), Some(&value.0))) + } + } + _ => Err(Error::new( + Status::InvalidArg, + format!( + "{:?} type could not deserialize to Enum type", + js_value_type + ), + )), + } + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'x>, + { + visitor.visit_unit() + } + + forward_to_deserialize_any! { + > + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + unit unit_struct seq tuple tuple_struct map struct identifier + newtype_struct + } +} + +#[doc(hidden)] +pub(crate) struct JsEnumAccess<'env> { + variant: String, + value: Option<&'env Value>, +} + +#[doc(hidden)] +impl<'env> JsEnumAccess<'env> { + fn new(variant: String, value: Option<&'env Value>) -> Self { + Self { variant, value } + } +} + +#[doc(hidden)] +impl<'de, 'env> EnumAccess<'de> for JsEnumAccess<'env> { + type Error = Error; + type Variant = JsVariantAccess<'env>; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant)> + where + V: DeserializeSeed<'de>, + { + use serde::de::IntoDeserializer; + let variant = self.variant.into_deserializer(); + let variant_access = JsVariantAccess { value: self.value }; + seed.deserialize(variant).map(|v| (v, variant_access)) + } +} + +#[doc(hidden)] +pub(crate) struct JsVariantAccess<'env> { + value: Option<&'env Value>, +} + +#[doc(hidden)] +impl<'de, 'env> VariantAccess<'de> for JsVariantAccess<'env> { + type Error = Error; + fn unit_variant(self) -> Result<()> { + match self.value { + Some(val) => { + let mut deserializer = De(val); + serde::de::Deserialize::deserialize(&mut deserializer) + } + None => Ok(()), + } + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.value { + Some(val) => { + let mut deserializer = De(val); + seed.deserialize(&mut deserializer) + } + None => Err(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )), + } + } + + fn tuple_variant(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(js_value) => { + let js_object = JsObject::from_raw(js_value.env, js_value.value)?; + if js_object.is_array()? { + let mut deserializer = + JsArrayAccess::new(&js_object, js_object.get_array_length_unchecked()?); + visitor.visit_seq(&mut deserializer) + } else { + Err(serde::de::Error::invalid_type( + Unexpected::Other("JsValue"), + &"tuple variant", + )) + } + } + None => Err(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )), + } + } + + fn struct_variant(self, _fields: &'static [&'static str], visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(js_value) => { + if let Ok(val) = JsObject::from_raw(js_value.env, js_value.value) { + let mut deserializer = JsObjectAccess::new(&val)?; + visitor.visit_map(&mut deserializer) + } else { + Err(serde::de::Error::invalid_type( + Unexpected::Other("JsValue"), + &"struct variant", + )) + } + } + _ => Err(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )), + } + } +} + +#[doc(hidden)] +struct JsArrayAccess<'env> { + input: &'env JsObject, + idx: u32, + len: u32, +} + +#[doc(hidden)] +impl<'env> JsArrayAccess<'env> { + fn new(input: &'env JsObject, len: u32) -> Self { + Self { input, idx: 0, len } + } +} + +#[doc(hidden)] +impl<'de, 'env> SeqAccess<'de> for JsArrayAccess<'env> { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result> + where + T: DeserializeSeed<'de>, + { + if self.idx >= self.len { + return Ok(None); + } + let v = self.input.get_index::(self.idx)?; + self.idx += 1; + + let mut de = De(&v.0); + seed.deserialize(&mut de).map(Some) + } +} + +#[doc(hidden)] +pub(crate) struct JsObjectAccess<'env> { + value: &'env JsObject, + properties: JsObject, + idx: u32, + property_len: u32, +} + +#[doc(hidden)] +impl<'env> JsObjectAccess<'env> { + fn new(value: &'env JsObject) -> Result { + let properties = value.get_property_names::()?; + let property_len = properties.get_array_length_unchecked()?; + Ok(Self { + value, + properties, + idx: 0, + property_len, + }) + } +} + +#[doc(hidden)] +impl<'de, 'env> MapAccess<'de> for JsObjectAccess<'env> { + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result> + where + K: DeserializeSeed<'de>, + { + if self.idx >= self.property_len { + return Ok(None); + } + + let prop_name = self.properties.get_index::(self.idx)?; + + let mut de = De(&prop_name.0); + seed.deserialize(&mut de).map(Some) + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: DeserializeSeed<'de>, + { + if self.idx >= self.property_len { + return Err(Error::new( + Status::InvalidArg, + format!("Index:{} out of range: {}", self.property_len, self.idx), + )); + } + let prop_name = self.properties.get_index::(self.idx)?; + let value: JsUnknown = self.value.get_property(&prop_name)?; + + self.idx += 1; + let mut de = De(&value.0); + let res = seed.deserialize(&mut de)?; + Ok(res) + } +} diff --git a/napi/src/js_values/mod.rs b/napi/src/js_values/mod.rs index 7770e68a..f542ead8 100644 --- a/napi/src/js_values/mod.rs +++ b/napi/src/js_values/mod.rs @@ -1,9 +1,14 @@ -use std::convert::From; +use std::convert::{From, TryFrom}; use std::ptr; use crate::error::check_status; use crate::{sys, Error, Result, Status}; +#[cfg(feature = "serde-json")] +mod de; +#[cfg(feature = "serde-json")] +mod ser; + mod arraybuffer; #[cfg(napi6)] mod bigint; @@ -27,10 +32,14 @@ pub use bigint::JsBigint; pub use boolean::JsBoolean; pub use buffer::JsBuffer; pub use class_property::Property; +#[cfg(feature = "serde-json")] +pub(crate) use de::De; pub use either::Either; pub use function::JsFunction; pub use number::JsNumber; pub use object::JsObject; +#[cfg(feature = "serde-json")] +pub(crate) use ser::Ser; pub use string::JsString; pub(crate) use tagged_object::TaggedObject; pub use undefined::JsUndefined; @@ -94,6 +103,13 @@ macro_rules! impl_napi_value_trait { }) } } + + impl TryFrom for $js_value { + type Error = Error; + fn try_from(value: JsUnknown) -> Result<$js_value> { + $js_value::from_raw(value.0.env, value.0.value) + } + } }; } @@ -204,8 +220,6 @@ impl_js_value_methods!(JsString); impl_js_value_methods!(JsObject); impl_js_value_methods!(JsFunction); impl_js_value_methods!(JsExternal); -#[cfg(napi6)] -impl_js_value_methods!(JsBigint); impl_js_value_methods!(JsSymbol); use ValueType::*; @@ -218,8 +232,6 @@ impl_napi_value_trait!(JsString, String); impl_napi_value_trait!(JsObject, Object); impl_napi_value_trait!(JsFunction, Function); impl_napi_value_trait!(JsExternal, External); -#[cfg(napi6)] -impl_napi_value_trait!(JsBigint, Bigint); impl_napi_value_trait!(JsSymbol, Symbol); impl NapiValue for JsUnknown { diff --git a/napi/src/js_values/object.rs b/napi/src/js_values/object.rs index 0a1144d4..4e4cdba3 100644 --- a/napi/src/js_values/object.rs +++ b/napi/src/js_values/object.rs @@ -21,28 +21,32 @@ impl JsObject { key: JsNumber, value: V, ) -> Result<()> { - let status = - unsafe { sys::napi_set_property(self.0.env, self.0.value, key.0.value, value.raw_value()) }; - check_status(status)?; - Ok(()) + check_status(unsafe { + sys::napi_set_property(self.0.env, self.0.value, key.0.value, value.raw_value()) + }) } pub fn set_named_property(&mut self, name: &str, value: T) -> Result<()> { let key = CString::new(name)?; - let status = unsafe { + check_status(unsafe { sys::napi_set_named_property(self.0.env, self.0.value, key.as_ptr(), value.raw_value()) - }; - check_status(status)?; - Ok(()) + }) } pub fn get_named_property(&self, name: &str) -> Result { let key = CString::new(name)?; let mut raw_value = ptr::null_mut(); - let status = unsafe { + check_status(unsafe { sys::napi_get_named_property(self.0.env, self.0.value, key.as_ptr(), &mut raw_value) - }; - check_status(status)?; + })?; + T::from_raw(self.0.env, raw_value) + } + + pub fn get_property(&self, key: &K) -> Result { + let mut raw_value = ptr::null_mut(); + check_status(unsafe { + sys::napi_get_property(self.0.env, self.0.value, key.raw_value(), &mut raw_value) + })?; T::from_raw(self.0.env, raw_value) } @@ -59,22 +63,21 @@ impl JsObject { pub fn get_index(&self, index: u32) -> Result { let mut raw_value = ptr::null_mut(); - let status = unsafe { sys::napi_get_element(self.0.env, self.0.value, index, &mut raw_value) }; - check_status(status)?; + check_status(unsafe { + sys::napi_get_element(self.0.env, self.0.value, index, &mut raw_value) + })?; T::from_raw(self.0.env, raw_value) } pub fn is_array(&self) -> Result { let mut is_array = false; - let status = unsafe { sys::napi_is_array(self.0.env, self.0.value, &mut is_array) }; - check_status(status)?; + check_status(unsafe { sys::napi_is_array(self.0.env, self.0.value, &mut is_array) })?; Ok(is_array) } pub fn is_buffer(&self) -> Result { let mut is_buffer = false; - let status = unsafe { sys::napi_is_buffer(self.0.env, self.0.value, &mut is_buffer) }; - check_status(status)?; + check_status(unsafe { sys::napi_is_buffer(self.0.env, self.0.value, &mut is_buffer) })?; Ok(is_buffer) } @@ -89,9 +92,13 @@ impl JsObject { "Object is not array".to_owned(), )); } + self.get_array_length_unchecked() + } + + #[inline] + pub fn get_array_length_unchecked(&self) -> Result { let mut length: u32 = 0; - let status = unsafe { sys::napi_get_array_length(self.0.env, self.raw_value(), &mut length) }; - check_status(status)?; + check_status(unsafe { sys::napi_get_array_length(self.0.env, self.raw_value(), &mut length) })?; Ok(length) } } diff --git a/napi/src/js_values/ser.rs b/napi/src/js_values/ser.rs new file mode 100644 index 00000000..aff74e06 --- /dev/null +++ b/napi/src/js_values/ser.rs @@ -0,0 +1,510 @@ +use std::result::Result as StdResult; +#[cfg(napi6)] +use std::slice; + +use serde::{ser, Serialize, Serializer}; + +use super::*; +use crate::{Env, Error, Result}; + +pub(crate) struct Ser<'env>(pub(crate) &'env Env); + +impl<'env> Ser<'env> { + fn new(env: &'env Env) -> Self { + Self(&env) + } +} + +impl<'env> Serializer for Ser<'env> { + type Ok = Value; + type Error = Error; + + type SerializeSeq = SeqSerializer; + type SerializeTuple = SeqSerializer; + type SerializeTupleStruct = SeqSerializer; + type SerializeTupleVariant = SeqSerializer; + type SerializeMap = MapSerializer; + type SerializeStruct = StructSerializer; + type SerializeStructVariant = StructSerializer; + + #[inline] + fn serialize_bool(self, v: bool) -> Result { + self.0.get_boolean(v).map(|js_value| js_value.0) + } + + #[inline] + fn serialize_bytes(self, v: &[u8]) -> Result { + self + .0 + .create_buffer_with_data(v.to_owned()) + .map(|js_value| js_value.value.0) + } + + #[inline] + fn serialize_char(self, v: char) -> Result { + let mut b = [0; 4]; + let result = v.encode_utf8(&mut b); + self.0.create_string(result).map(|js_string| js_string.0) + } + + #[inline] + fn serialize_f32(self, v: f32) -> Result { + self.0.create_double(v as _).map(|js_number| js_number.0) + } + + #[inline] + fn serialize_f64(self, v: f64) -> Result { + self.0.create_double(v).map(|js_number| js_number.0) + } + + #[inline] + fn serialize_i16(self, v: i16) -> Result { + self.0.create_int32(v as _).map(|js_number| js_number.0) + } + + #[inline] + fn serialize_i32(self, v: i32) -> Result { + self.0.create_int32(v).map(|js_number| js_number.0) + } + + #[inline] + fn serialize_i64(self, v: i64) -> Result { + self.0.create_int64(v).map(|js_number| js_number.0) + } + + #[inline] + fn serialize_i8(self, v: i8) -> Result { + self.0.create_int32(v as _).map(|js_number| js_number.0) + } + + #[inline] + fn serialize_u8(self, v: u8) -> Result { + self.0.create_uint32(v as _).map(|js_number| js_number.0) + } + + #[inline] + fn serialize_u16(self, v: u16) -> Result { + self.0.create_uint32(v as _).map(|js_number| js_number.0) + } + + #[inline] + fn serialize_u32(self, v: u32) -> Result { + self.0.create_uint32(v).map(|js_number| js_number.0) + } + + #[cfg(all(any(napi2, napi3, napi4, napi5), not(napi6)))] + #[inline] + fn serialize_u64(self, v: u64) -> Result { + self.0.create_int64(v as _).map(|js_number| js_number.0) + } + + #[cfg(napi6)] + #[inline] + fn serialize_u64(self, v: u64) -> Result { + self + .0 + .create_bigint_from_u64(v) + .map(|js_number| js_number.raw) + } + + #[cfg(all(any(napi2, napi3, napi4, napi5), not(napi6)))] + #[inline] + fn serialize_u128(self, v: u128) -> Result { + self.0.create_string(v.to_string().as_str()).map(|v| v.0) + } + + #[cfg(napi6)] + #[inline] + fn serialize_u128(self, v: u128) -> Result { + let words_ref = &v as *const _; + let words = unsafe { slice::from_raw_parts(words_ref as *const u64, 2) }; + self + .0 + .create_bigint_from_words(false, words.to_vec()) + .map(|v| v.raw) + } + + #[cfg(all(any(napi2, napi3, napi4, napi5), not(napi6)))] + #[inline] + fn serialize_i128(self, v: i128) -> Result { + self.0.create_string(v.to_string().as_str()).map(|v| v.0) + } + + #[cfg(napi6)] + #[inline] + fn serialize_i128(self, v: i128) -> Result { + let words_ref = &(v as u128) as *const _; + let words = unsafe { slice::from_raw_parts(words_ref as *const u64, 2) }; + self + .0 + .create_bigint_from_words(v < 0, words.to_vec()) + .map(|v| v.raw) + } + + #[inline] + fn serialize_unit(self) -> Result { + self.0.get_null().map(|null| null.0) + } + + #[inline] + fn serialize_none(self) -> Result { + self.0.get_null().map(|null| null.0) + } + + #[inline] + fn serialize_str(self, v: &str) -> Result { + self.0.create_string(v).map(|string| string.0) + } + + #[inline] + fn serialize_some(self, value: &T) -> Result + where + T: Serialize, + { + value.serialize(self) + } + + #[inline] + fn serialize_map(self, _len: Option) -> Result { + let env = self.0; + let key = env.create_string("")?; + let obj = env.create_object()?; + Ok(MapSerializer { key, obj }) + } + + #[inline] + fn serialize_seq(self, len: Option) -> Result { + let array = self.0.create_array_with_length(len.unwrap_or(0))?; + Ok(SeqSerializer { + current_index: 0, + array, + }) + } + + #[inline] + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + let env = self.0; + let array = env.create_array_with_length(len)?; + let mut object = env.create_object()?; + object.set_named_property( + variant, + JsObject(Value { + value: array.0.value, + env: array.0.env, + value_type: ValueType::Object, + }), + )?; + Ok(SeqSerializer { + current_index: 0, + array, + }) + } + + #[inline] + fn serialize_unit_struct(self, _name: &'static str) -> Result { + self.0.get_null().map(|null| null.0) + } + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result { + self.0.create_string(variant).map(|string| string.0) + } + + #[inline] + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result + where + T: Serialize, + { + value.serialize(self) + } + + #[inline] + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result + where + T: Serialize, + { + let mut obj = self.0.create_object()?; + obj.set_named_property(variant, JsUnknown(value.serialize(self)?))?; + Ok(obj.0) + } + + #[inline] + fn serialize_tuple(self, len: usize) -> Result { + Ok(SeqSerializer { + array: self.0.create_array_with_length(len)?, + current_index: 0, + }) + } + + #[inline] + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result { + Ok(SeqSerializer { + array: self.0.create_array_with_length(len)?, + current_index: 0, + }) + } + + #[inline] + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + Ok(StructSerializer { + obj: self.0.create_object()?, + }) + } + + #[inline] + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + _len: usize, + ) -> Result { + let mut outer = self.0.create_object()?; + let inner = self.0.create_object()?; + outer.set_named_property( + variant, + JsObject(Value { + env: inner.0.env, + value: inner.0.value, + value_type: ValueType::Object, + }), + )?; + Ok(StructSerializer { + obj: self.0.create_object()?, + }) + } +} + +pub struct SeqSerializer { + array: JsObject, + current_index: usize, +} + +impl ser::SerializeSeq for SeqSerializer { + type Ok = Value; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> StdResult<(), Self::Error> + where + T: Serialize, + { + let env = Env::from_raw(self.array.0.env); + self.array.set_index( + self.current_index, + JsUnknown(value.serialize(Ser::new(&env))?), + )?; + self.current_index = self.current_index + 1; + Ok(()) + } + + fn end(self) -> Result { + Ok(self.array.0) + } +} + +#[doc(hidden)] +impl ser::SerializeTuple for SeqSerializer { + type Ok = Value; + type Error = Error; + + #[inline] + fn serialize_element(&mut self, value: &T) -> StdResult<(), Self::Error> + where + T: Serialize, + { + let env = Env::from_raw(self.array.0.env); + self.array.set_index( + self.current_index, + JsUnknown(value.serialize(Ser::new(&env))?), + )?; + self.current_index = self.current_index + 1; + Ok(()) + } + + #[inline] + fn end(self) -> StdResult { + Ok(self.array.0) + } +} + +#[doc(hidden)] +impl ser::SerializeTupleStruct for SeqSerializer { + type Ok = Value; + type Error = Error; + + #[inline] + fn serialize_field(&mut self, value: &T) -> StdResult<(), Self::Error> + where + T: Serialize, + { + let env = Env::from_raw(self.array.0.env); + self.array.set_index( + self.current_index, + JsUnknown(value.serialize(Ser::new(&env))?), + )?; + self.current_index = self.current_index + 1; + Ok(()) + } + + #[inline] + fn end(self) -> StdResult { + Ok(self.array.0) + } +} + +#[doc(hidden)] +impl ser::SerializeTupleVariant for SeqSerializer { + type Ok = Value; + type Error = Error; + + #[inline] + fn serialize_field(&mut self, value: &T) -> StdResult<(), Self::Error> + where + T: Serialize, + { + let env = Env::from_raw(self.array.0.env); + self.array.set_index( + self.current_index, + JsUnknown(value.serialize(Ser::new(&env))?), + )?; + self.current_index = self.current_index + 1; + Ok(()) + } + + #[inline] + fn end(self) -> Result { + Ok(self.array.0) + } +} + +pub struct MapSerializer { + key: JsString, + obj: JsObject, +} + +#[doc(hidden)] +impl ser::SerializeMap for MapSerializer { + type Ok = Value; + type Error = Error; + + #[inline] + fn serialize_key(&mut self, key: &T) -> StdResult<(), Self::Error> + where + T: Serialize, + { + let env = Env::from_raw(self.obj.0.env); + self.key = JsString(key.serialize(Ser::new(&env))?); + Ok(()) + } + + #[inline] + fn serialize_value(&mut self, value: &T) -> StdResult<(), Self::Error> + where + T: Serialize, + { + let env = Env::from_raw(self.obj.0.env); + self.obj.set_property( + JsString(Value { + env: self.key.0.env, + value: self.key.0.value, + value_type: ValueType::String, + }), + JsUnknown(value.serialize(Ser::new(&env))?), + )?; + Ok(()) + } + + #[inline] + fn serialize_entry( + &mut self, + key: &K, + value: &V, + ) -> StdResult<(), Self::Error> + where + K: Serialize, + V: Serialize, + { + let env = Env::from_raw(self.obj.0.env); + self.obj.set_property( + JsString(key.serialize(Ser::new(&env))?), + JsUnknown(value.serialize(Ser::new(&env))?), + )?; + Ok(()) + } + + #[inline] + fn end(self) -> Result { + Ok(self.obj.0) + } +} + +pub struct StructSerializer { + obj: JsObject, +} + +#[doc(hidden)] +impl ser::SerializeStruct for StructSerializer { + type Ok = Value; + type Error = Error; + + #[inline] + fn serialize_field(&mut self, key: &'static str, value: &T) -> StdResult<(), Error> + where + T: Serialize, + { + let env = Env::from_raw(self.obj.0.env); + self + .obj + .set_named_property(key, JsUnknown(value.serialize(Ser::new(&env))?))?; + Ok(()) + } + + #[inline] + fn end(self) -> Result { + Ok(self.obj.0) + } +} + +#[doc(hidden)] +impl ser::SerializeStructVariant for StructSerializer { + type Ok = Value; + type Error = Error; + + #[inline] + fn serialize_field(&mut self, key: &'static str, value: &T) -> StdResult<(), Error> + where + T: Serialize, + { + let env = Env::from_raw(self.obj.0.env); + self + .obj + .set_named_property(key, JsUnknown(value.serialize(Ser::new(&env))?))?; + Ok(()) + } + + #[inline] + fn end(self) -> Result { + Ok(self.obj.0) + } +} diff --git a/napi/src/js_values/string.rs b/napi/src/js_values/string.rs index da8f599f..e87e965b 100644 --- a/napi/src/js_values/string.rs +++ b/napi/src/js_values/string.rs @@ -47,6 +47,30 @@ impl JsString { } } + #[inline] + pub fn chars(&self) -> Result<&[char]> { + let mut written_char_count: u64 = 0; + let len = self.len()? + 1; + let mut result = Vec::with_capacity(len); + unsafe { + let status = sys::napi_get_value_string_utf8( + self.0.env, + self.0.value, + result.as_mut_ptr(), + len as u64, + &mut written_char_count, + ); + + check_status(status)?; + let ptr = result.as_ptr(); + mem::forget(result); + Ok(slice::from_raw_parts( + ptr as *const char, + written_char_count as usize, + )) + } + } + pub fn as_str(&self) -> Result<&str> { str::from_utf8(self.get_ref()?) .map_err(|e| Error::new(Status::GenericFailure, format!("{:?}", e))) diff --git a/napi/src/js_values/value.rs b/napi/src/js_values/value.rs index fb9f8137..0d575fa8 100644 --- a/napi/src/js_values/value.rs +++ b/napi/src/js_values/value.rs @@ -2,7 +2,7 @@ use crate::sys; use super::ValueType; -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub struct Value { pub env: sys::napi_env, pub value: sys::napi_value, diff --git a/napi/src/lib.rs b/napi/src/lib.rs index 686e0485..e2e5411c 100644 --- a/napi/src/lib.rs +++ b/napi/src/lib.rs @@ -88,6 +88,10 @@ pub use version::NodeVersion; #[cfg(all(feature = "tokio_rt", napi4))] pub use tokio_rt::shutdown as shutdown_tokio_rt; +#[cfg(feature = "serde-json")] +#[macro_use] +extern crate serde; + /// register nodejs module /// /// ## Example diff --git a/napi/src/threadsafe_function.rs b/napi/src/threadsafe_function.rs index 68f2e561..92e0b1eb 100644 --- a/napi/src/threadsafe_function.rs +++ b/napi/src/threadsafe_function.rs @@ -1,3 +1,4 @@ +use std::convert::Into; use std::os::raw::{c_char, c_void}; use std::ptr; @@ -7,6 +8,44 @@ use crate::{sys, Env, JsFunction, JsUnknown, Result}; use sys::napi_threadsafe_function_call_mode; use sys::napi_threadsafe_function_release_mode; +#[repr(u8)] +pub enum ThreadsafeFunctionCallMode { + NonBlocking, + Blocking, +} + +#[repr(u8)] +pub enum ThreadsafeFunctionReleaseMode { + Release, + Abort, +} + +impl Into for ThreadsafeFunctionCallMode { + fn into(self) -> napi_threadsafe_function_call_mode { + match self { + ThreadsafeFunctionCallMode::Blocking => { + napi_threadsafe_function_call_mode::napi_tsfn_blocking + } + ThreadsafeFunctionCallMode::NonBlocking => { + napi_threadsafe_function_call_mode::napi_tsfn_nonblocking + } + } + } +} + +impl Into for ThreadsafeFunctionReleaseMode { + fn into(self) -> napi_threadsafe_function_release_mode { + match self { + ThreadsafeFunctionReleaseMode::Release => { + napi_threadsafe_function_release_mode::napi_tsfn_release + } + ThreadsafeFunctionReleaseMode::Abort => { + napi_threadsafe_function_release_mode::napi_tsfn_abort + } + } + } +} + pub trait ToJs: Copy + Clone { type Output; @@ -25,17 +64,9 @@ pub trait ToJs: Copy + Clone { /// use std::thread; /// use napi::{ /// Number, Result, Env, CallContext, JsUndefined, JsFunction, -/// sys::{ -/// napi_threadsafe_function_call_mode::{ -/// napi_tsfn_blocking, -/// }, -/// napi_threadsafe_function_release_mode::{ -/// napi_tsfn_release, -/// } -/// } /// }; /// use napi::threadsafe_function::{ -/// ToJs, ThreadsafeFunction, +/// ToJs, ThreadsafeFunction, ThreadsafeFunctionCallMode, ThreadsafeFunctionReleaseMode, /// }; /// /// // Define a struct for handling the data passed from `ThreadsafeFunction::call` @@ -67,12 +98,12 @@ pub trait ToJs: Copy + Clone { /// thread::spawn(move || { /// let output: u8 = 42; /// // It's okay to call a threadsafe function multiple times. -/// tsfn.call(Ok(output), napi_tsfn_blocking).unwrap(); -/// tsfn.call(Ok(output), napi_tsfn_blocking).unwrap(); +/// tsfn.call(Ok(output), ThreadsafeFunctionCallMode::Blocking).unwrap(); +/// tsfn.call(Ok(output), ThreadsafeFunctionCallMode::Blocking).unwrap(); /// // We should call `ThreadsafeFunction::release` manually when we don't /// // need the instance anymore, or it will prevent Node.js from exiting /// // automatically and possibly cause memory leaks. -/// tsfn.release(napi_tsfn_release).unwrap(); +/// tsfn.release(ThreadsafeFunctionReleaseMode::Release).unwrap(); /// }); /// /// ctx.env.get_undefined() @@ -137,16 +168,12 @@ impl ThreadsafeFunction { /// See [napi_call_threadsafe_function](https://nodejs.org/api/n-api.html#n_api_napi_call_threadsafe_function) /// for more information. - pub fn call( - &self, - value: Result, - mode: napi_threadsafe_function_call_mode, - ) -> Result<()> { + pub fn call(&self, value: Result, mode: ThreadsafeFunctionCallMode) -> Result<()> { check_status(unsafe { sys::napi_call_threadsafe_function( self.raw_value, Box::into_raw(Box::from(value)) as *mut _ as *mut c_void, - mode, + mode.into(), ) }) } @@ -159,8 +186,8 @@ impl ThreadsafeFunction { /// See [napi_release_threadsafe_function](https://nodejs.org/api/n-api.html#n_api_napi_release_threadsafe_function) /// for more information. - pub fn release(&self, mode: napi_threadsafe_function_release_mode) -> Result<()> { - check_status(unsafe { sys::napi_release_threadsafe_function(self.raw_value, mode) }) + pub fn release(&self, mode: ThreadsafeFunctionReleaseMode) -> Result<()> { + check_status(unsafe { sys::napi_release_threadsafe_function(self.raw_value, mode.into()) }) } /// See [napi_ref_threadsafe_function](https://nodejs.org/api/n-api.html#n_api_napi_ref_threadsafe_function) diff --git a/test_module/Cargo.toml b/test_module/Cargo.toml index c0e3f30d..8e02d109 100644 --- a/test_module/Cargo.toml +++ b/test_module/Cargo.toml @@ -9,8 +9,12 @@ crate-type = ["cdylib"] [dependencies] futures = "0.3" -napi = { path = "../napi", features = ["libuv", "tokio_rt"] } +napi = { path = "../napi", features = ["libuv", "tokio_rt", "serde-json"] } napi-derive = { path = "../napi-derive" } +serde = "1" +serde_bytes = "0.11" +serde_derive = "1" +serde_json = "1" tokio = { version = "0.2", features = ["default", "fs"]} [build-dependencies] diff --git a/test_module/__test__/napi-version.ts b/test_module/__test__/napi-version.ts index 2d277819..6cab1562 100644 --- a/test_module/__test__/napi-version.ts +++ b/test_module/__test__/napi-version.ts @@ -1,2 +1 @@ -// @ts-expect-error -export const napiVersion = parseInt(process.versions.napi || '1', 10) +export const napiVersion = parseInt(process.versions.napi ?? '1', 10) diff --git a/test_module/__test__/serde/de.spec.ts b/test_module/__test__/serde/de.spec.ts new file mode 100644 index 00000000..3281c006 --- /dev/null +++ b/test_module/__test__/serde/de.spec.ts @@ -0,0 +1,39 @@ +import test from 'ava' + +import { napiVersion } from '../napi-version' + +const bindings = require('../../index.node') + +test('deserialize string', (t) => { + t.notThrows(() => bindings.expect_hello_world('hello world')) +}) + +test('deserialize object', (t) => { + if (napiVersion < 6) { + t.throws(() => { + bindings.expect_obj({}) + }) + } else { + t.notThrows(() => + bindings.expect_obj({ + a: 1, + b: [1, 2], + c: 'abc', + d: false, + e: null, + f: null, + g: [9, false, 'efg'], + h: '🤷', + i: 'Empty', + j: { Tuple: [27, 'hij'] }, + k: { Struct: { a: 128, b: [9, 8, 7] } }, + l: 'jkl', + m: [0, 1, 2, 3, 4], + o: { Value: ['z', 'y', 'x'] }, + p: [1, 2, 3.5], + q: BigInt('9998881288248882845242411222333'), + r: BigInt('-3332323888900001232323022221345'), + }), + ) + } +}) diff --git a/test_module/__test__/serde/ser.spec.ts b/test_module/__test__/serde/ser.spec.ts new file mode 100644 index 00000000..24d46fa0 --- /dev/null +++ b/test_module/__test__/serde/ser.spec.ts @@ -0,0 +1,26 @@ +import test from 'ava' + +import { napiVersion } from '../napi-version' + +const bindings = require('../../index.node') + +const testFunc = [ + 'make_num_77', + 'make_num_32', + 'make_str_hello', + 'make_num_array', + 'make_buff', + 'make_obj', + 'make_map', +] + +if (napiVersion >= 6) { + // bigint inside + testFunc.push('make_object') +} + +for (const func of testFunc) { + test(`serialize ${func} from bindings`, (t) => { + t.snapshot(bindings[func]()) + }) +} diff --git a/test_module/__test__/serde/ser.spec.ts.md b/test_module/__test__/serde/ser.spec.ts.md new file mode 100644 index 00000000..00620da3 --- /dev/null +++ b/test_module/__test__/serde/ser.spec.ts.md @@ -0,0 +1,130 @@ +# Snapshot report for `test_module/__test__/serde/ser.spec.ts` + +The actual snapshot is saved in `ser.spec.ts.snap`. + +Generated by [AVA](https://avajs.dev). + +## serialize make_buff from bindings + +> Snapshot 1 + + Buffer @Uint8Array [ + fffefd + ] + +## serialize make_map from bindings + +> Snapshot 1 + + { + a: 1, + b: 2, + c: 3, + } + +## serialize make_num_32 from bindings + +> Snapshot 1 + + 32 + +## serialize make_num_77 from bindings + +> Snapshot 1 + + 77 + +## serialize make_num_array from bindings + +> Snapshot 1 + + [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + ] + +## serialize make_obj from bindings + +> Snapshot 1 + + { + a: 1, + b: [ + 0.1, + 1.1, + 2.2, + 3.3, + ], + c: 'Hi', + } + +## serialize make_object from bindings + +> Snapshot 1 + + { + a: 1, + b: [ + 1, + 2, + ], + c: 'abc', + d: false, + e: null, + f: null, + g: [ + 9, + false, + 'efg', + ], + h: '🤷', + i: 'Empty', + j: [ + 27, + 'hij', + ], + k: { + a: 128, + b: [ + 9, + 8, + 7, + ], + }, + l: 'jkl', + m: [ + 0, + 1, + 2, + 3, + 4, + ], + o: { + Value: [ + 'z', + 'y', + 'x', + ], + }, + p: [ + 1, + 2, + 3.5, + ], + q: 9998881288248882845242411222333n, + r: -340282363588614574563373375108745990111n, + } + +## serialize make_str_hello from bindings + +> Snapshot 1 + + 'Hello World' diff --git a/test_module/__test__/serde/ser.spec.ts.snap b/test_module/__test__/serde/ser.spec.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..da74db6c6b3d928e2c0673199dce52b3ecc75aeb GIT binary patch literal 1038 zcmV+p1o8VpRzVr00000000B6 zm0O4#RT#(5nKP4Q(~U`1vGvyNWAPGqW|DLQVr{W?(UsN3tq7tfo5?1-X|{%JyQ_%B z3$+hLsTEd>wJwVymKKDzXsbTtam5R+LNEJJ5Tylat7!GXuKzhZXEJj(wt|NI$eI87 z&-dk=?_9nogha>qN7?S?`s+_tC~-b9@LRm^X!qQ%Qb|(7V+2TCqstMRDU+xAs%6>IhoecIZg*&bj*Z zz4^W;-+uRg%GEc)V*`_y;7+M?h6VAM`)0@*Xsjq|18kYISVYqhs}I z(d&rNWe?$Z6R^Qnumeni55Om27Mun@gKKFhNwszLdVZ2p(Td08ghu(d6Ap!3N12n~ zeWY~pnNlGruAm5kxdIb{>I$k5G*{4s5ORf(5W=ny7DB`oB0}hJg${4@D=Ew3_a3lO zj4rf(yi~I5&hVmxm0H7E9Ag4w>?U25EnNPK&=_$>6L-S$pc>4D$%fr$*M=KqF&f`2 zt4^M~z#u4lx%vwu_E5vg?%IqK8AMLTJCE|;?`OE)abNTXp`>5P#!(zO0JIk6{^R*34K|R!?Wvq%&F5T!U{$@3HWd%k}8G?kpnqJpRqg;0<=AO@&4O9t;P- zaqxv?W|Enmf#D}`NiwRku@eVv7r0%O)}a<$hY=cD3(E%Z2(ZCcutN>T4@>ctDH!(2 zu_JP9^)M{Qz$`c|#f-|wixNCuS~ml2ZQm&It^;A~2-=)w?>~H;g=Ck8+h({a_^M+q zS4Q~mTyj*nyHnXt_-ebT2DfLFc(>61d($mmD#*A}Yh~0n<*Va%+v#XGYw}@irZT)d z4 Result<()> { + serde::register_serde_func(module)?; module.create_named_method("testThrow", test_throw)?; module.create_named_method("testThrowWithReason", test_throw_with_reason)?; module.create_named_method("testSpawnThread", test_spawn_thread)?; diff --git a/test_module/src/napi4/tsfn.rs b/test_module/src/napi4/tsfn.rs index 459cb22c..777795fa 100644 --- a/test_module/src/napi4/tsfn.rs +++ b/test_module/src/napi4/tsfn.rs @@ -1,15 +1,10 @@ use std::path::Path; use std::thread; -use napi::sys::{ - napi_threadsafe_function_call_mode::napi_tsfn_blocking, - napi_threadsafe_function_release_mode::napi_tsfn_release, -}; -use napi::threadsafe_function::{ThreadsafeFunction, ToJs}; -use napi::{ - CallContext, Env, Error, JsFunction, JsString, JsUndefined, Result, Status, - JsUnknown, +use napi::threadsafe_function::{ + ThreadsafeFunction, ThreadsafeFunctionCallMode, ThreadsafeFunctionReleaseMode, ToJs, }; +use napi::{CallContext, Env, Error, JsFunction, JsString, JsUndefined, JsUnknown, Result, Status}; use tokio; #[derive(Clone, Copy)] @@ -38,9 +33,15 @@ pub fn test_threadsafe_function(ctx: CallContext) -> Result { thread::spawn(move || { let output: Vec = vec![42, 1, 2, 3]; // It's okay to call a threadsafe function multiple times. - tsfn.call(Ok(output.clone()), napi_tsfn_blocking).unwrap(); - tsfn.call(Ok(output.clone()), napi_tsfn_blocking).unwrap(); - tsfn.release(napi_tsfn_release).unwrap(); + tsfn + .call(Ok(output.clone()), ThreadsafeFunctionCallMode::Blocking) + .unwrap(); + tsfn + .call(Ok(output.clone()), ThreadsafeFunctionCallMode::Blocking) + .unwrap(); + tsfn + .release(ThreadsafeFunctionReleaseMode::Release) + .unwrap(); }); ctx.env.get_undefined() @@ -56,10 +57,12 @@ pub fn test_tsfn_error(ctx: CallContext) -> Result { tsfn .call( Err(Error::new(Status::Unknown, "invalid".to_owned())), - napi_tsfn_blocking, + ThreadsafeFunctionCallMode::Blocking, ) .unwrap(); - tsfn.release(napi_tsfn_release).unwrap(); + tsfn + .release(ThreadsafeFunctionReleaseMode::Release) + .unwrap(); }); ctx.env.get_undefined() @@ -72,7 +75,9 @@ impl ToJs for HandleBuffer { type Output = Vec; fn resolve(&self, env: &mut Env, output: Self::Output) -> Result> { - let value = env.create_buffer_with_data(output.to_vec())?.into_unknown()?; + let value = env + .create_buffer_with_data(output.to_vec())? + .into_unknown()?; Ok(vec![value]) } } @@ -96,8 +101,10 @@ pub fn test_tokio_readfile(ctx: CallContext) -> Result { rt.block_on(async move { let mut filepath = Path::new(path_str); let ret = read_file_content(&mut filepath).await; - let _ = tsfn.call(ret, napi_tsfn_blocking); - tsfn.release(napi_tsfn_release).unwrap(); + let _ = tsfn.call(ret, ThreadsafeFunctionCallMode::Blocking); + tsfn + .release(ThreadsafeFunctionReleaseMode::Release) + .unwrap(); }); ctx.env.get_undefined() diff --git a/test_module/src/napi6/bigint.rs b/test_module/src/napi6/bigint.rs index 1d8781bd..faac2761 100644 --- a/test_module/src/napi6/bigint.rs +++ b/test_module/src/napi6/bigint.rs @@ -1,5 +1,5 @@ +use napi::{CallContext, JsBigint, JsNumber, JsObject, Result}; use std::convert::TryFrom; -use napi::{CallContext, JsBigint, Result, JsNumber, JsObject}; #[js_function(0)] pub fn test_create_bigint_from_i64(ctx: CallContext) -> Result { @@ -13,7 +13,9 @@ pub fn test_create_bigint_from_u64(ctx: CallContext) -> Result { #[js_function(0)] pub fn test_create_bigint_from_words(ctx: CallContext) -> Result { - ctx.env.create_bigint_from_words(true, vec![u64::max_value(), u64::max_value()]) + ctx + .env + .create_bigint_from_words(true, vec![u64::max_value(), u64::max_value()]) } #[js_function(1)] @@ -32,16 +34,18 @@ pub fn test_get_bigint_u64(ctx: CallContext) -> Result { #[js_function(0)] pub fn test_get_bigint_words(ctx: CallContext) -> Result { - let js_bigint = ctx.env.create_bigint_from_words(true, vec![i64::max_value() as u64, i64::max_value() as u64])?; + let mut js_bigint = ctx + .env + .create_bigint_from_words(true, vec![i64::max_value() as u64, i64::max_value() as u64])?; let mut js_arr = ctx.env.create_array_with_length(2)?; - let words = js_bigint.get_words(true)?; + let (_signed, words) = js_bigint.get_words()?; js_arr.set_number_indexed_property( ctx.env.create_int64(0)?, - ctx.env.create_bigint_from_u64(words[0])? + ctx.env.create_bigint_from_u64(words[0])?, )?; js_arr.set_number_indexed_property( ctx.env.create_int64(1)?, - ctx.env.create_bigint_from_u64(words[1])? + ctx.env.create_bigint_from_u64(words[1])?, )?; Ok(js_arr) } diff --git a/test_module/src/serde.rs b/test_module/src/serde.rs new file mode 100644 index 00000000..ebc2ce14 --- /dev/null +++ b/test_module/src/serde.rs @@ -0,0 +1,182 @@ +use napi::{CallContext, JsObject, JsUndefined, JsUnknown, Module, Result}; + +#[derive(Serialize, Debug, Deserialize)] +struct AnObject { + a: u32, + b: Vec, + c: String, +} + +#[derive(Serialize, Debug, Deserialize, Eq, PartialEq)] +struct Inner; + +#[derive(Serialize, Debug, Deserialize, Eq, PartialEq)] +struct Inner2(i32, bool, String); + +#[derive(Serialize, Debug, Deserialize, Eq, PartialEq)] +enum TypeEnum { + Empty, + Tuple(u32, String), + Struct { a: u8, b: Vec }, + Value(Vec), +} + +#[derive(Serialize, Debug, Deserialize, PartialEq)] +struct AnObjectTwo { + a: u32, + b: Vec, + c: String, + d: Option, + e: Option, + f: Inner, + g: Inner2, + h: char, + i: TypeEnum, + j: TypeEnum, + k: TypeEnum, + l: String, + m: Vec, + o: TypeEnum, + p: Vec, + q: u128, + r: i128, +} + +macro_rules! make_test { + ($name:ident, $val:expr) => { + #[js_function] + fn $name(ctx: CallContext) -> Result { + let value = $val; + ctx.env.to_js_value(&value) + } + }; +} + +make_test!(make_num_77, 77i32); +make_test!(make_num_32, 32u8); +make_test!(make_str_hello, "Hello World"); +make_test!(make_num_array, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); +make_test!( + make_obj, + AnObject { + a: 1, + b: vec![0.1f64, 1.1, 2.2, 3.3], + c: "Hi".into(), + } +); +make_test!(make_map, { + use std::collections::HashMap; + let mut map = HashMap::new(); + map.insert("a", 1); + map.insert("b", 2); + map.insert("c", 3); + map +}); + +make_test!(make_object, { + let value = AnObjectTwo { + a: 1, + b: vec![1, 2], + c: "abc".into(), + d: Some(false), + e: None, + f: Inner, + g: Inner2(9, false, "efg".into()), + h: '🤷', + i: TypeEnum::Empty, + j: TypeEnum::Tuple(27, "hij".into()), + k: TypeEnum::Struct { + a: 128, + b: vec![9, 8, 7], + }, + l: "jkl".into(), + m: vec![0, 1, 2, 3, 4], + o: TypeEnum::Value(vec!['z', 'y', 'x']), + p: vec![1., 2., 3.5], + q: 9998881288248882845242411222333, + r: -3332323888900001232323022221345, + }; + value +}); + +const NUMBER_BYTES: &'static [u8] = &[255u8, 254, 253]; + +make_test!(make_buff, { serde_bytes::Bytes::new(NUMBER_BYTES) }); + +macro_rules! make_expect { + ($name:ident, $val:expr, $val_type:ty) => { + #[js_function(1)] + fn $name(ctx: CallContext) -> Result { + let value = $val; + let arg0 = ctx.get::(0)?; + + let de_serialized: $val_type = ctx.env.from_js_value(arg0)?; + assert_eq!(value, de_serialized); + ctx.env.get_undefined() + } + }; +} + +make_expect!(expect_hello_world, "hello world", String); + +make_expect!( + expect_obj, + AnObjectTwo { + a: 1, + b: vec![1, 2], + c: "abc".into(), + d: Some(false), + e: None, + f: Inner, + g: Inner2(9, false, "efg".into()), + h: '🤷', + i: TypeEnum::Empty, + j: TypeEnum::Tuple(27, "hij".into()), + k: TypeEnum::Struct { + a: 128, + b: vec![9, 8, 7], + }, + l: "jkl".into(), + m: vec![0, 1, 2, 3, 4], + o: TypeEnum::Value(vec!['z', 'y', 'x']), + p: vec![1., 2., 3.5], + q: 9998881288248882845242411222333, + r: -3332323888900001232323022221345, + }, + AnObjectTwo +); + +make_expect!(expect_num_array, vec![0, 1, 2, 3], Vec); + +make_expect!( + expect_buffer, + serde_bytes::ByteBuf::from(vec![252u8, 251, 250]), + serde_bytes::ByteBuf +); + +#[js_function(1)] +fn roundtrip_object(ctx: CallContext) -> Result { + let arg0 = ctx.get::(0)?; + + let de_serialized: AnObjectTwo = ctx.env.from_js_value(arg0)?; + ctx.env.to_js_value(&de_serialized) +} + +pub fn register_serde_func(m: &mut Module) -> Result<()> { + m.create_named_method("make_num_77", make_num_77)?; + m.create_named_method("make_num_32", make_num_32)?; + m.create_named_method("make_str_hello", make_str_hello)?; + m.create_named_method("make_num_array", make_num_array)?; + m.create_named_method("make_buff", make_buff)?; + m.create_named_method("make_obj", make_obj)?; + m.create_named_method("make_object", make_object)?; + m.create_named_method("make_map", make_map)?; + + m.create_named_method("expect_hello_world", expect_hello_world)?; + m.create_named_method("expect_obj", expect_obj)?; + m.create_named_method("expect_num_array", expect_num_array)?; + m.create_named_method("expect_buffer", expect_buffer)?; + + m.create_named_method("roundtrip_object", roundtrip_object)?; + Ok(()) +} From bb56818bea9f2b3b078569113e3d0124da23f4a7 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Tue, 1 Sep 2020 23:20:55 +0800 Subject: [PATCH 2/2] chore: upgrade deps --- package.json | 14 +- tsconfig.json | 15 +-- yarn.lock | 359 ++++++++++++++++++++++---------------------------- 3 files changed, 170 insertions(+), 218 deletions(-) diff --git a/package.json b/package.json index b6abfe67..cab1a1ee 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ }, "homepage": "https://github.com/napi-rs/napi-rs#readme", "dependencies": { - "clipanion": "^2.4.4", + "clipanion": "^2.5.0", "inquirer": "^7.3.3", "toml": "^3.0.0" }, @@ -58,13 +58,13 @@ }, "devDependencies": { "@istanbuljs/nyc-config-typescript": "^1.0.1", - "@swc-node/register": "^0.4.2", + "@swc-node/register": "^0.4.5", "@types/inquirer": "^7.3.1", - "@types/node": "^14.6.0", - "@typescript-eslint/eslint-plugin": "^4.0.0", - "@typescript-eslint/parser": "^3.10.1", + "@types/node": "^14.6.2", + "@typescript-eslint/eslint-plugin": "^4.0.1", + "@typescript-eslint/parser": "^4.0.1", "ava": "^3.12.1", - "eslint": "^7.7.0", + "eslint": "^7.8.0", "eslint-config-prettier": "^6.11.0", "eslint-plugin-import": "^2.22.0", "eslint-plugin-prettier": "^3.1.4", @@ -78,7 +78,7 @@ "typescript": "^4.0.2" }, "optionalDependencies": { - "@swc-node/core-linux-musl": "^0.6.0", + "@swc-node/core-linux-musl": "^0.6.1", "tslib": "^2.0.1" } } diff --git a/tsconfig.json b/tsconfig.json index 7c3b1697..309c5db5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,25 +20,14 @@ "suppressExcessPropertyErrors": true, "forceConsistentCasingInFileNames": true, "preserveSymlinks": true, - "target": "ES2015", + "target": "ES2018", "sourceMap": true, "esModuleInterop": true, "stripInternal": true, "resolveJsonModule": true, "importsNotUsedAsValues": "remove", "outDir": "./scripts", - "lib": [ - "dom", - "DOM.Iterable", - "ES5", - "ES2015", - "ES2016", - "ES2017", - "ES2018", - "ES2019", - "ES2020", - "esnext" - ] + "lib": ["dom", "DOM.Iterable", "ES2019", "ES2020", "esnext"] }, "include": ["./src"], "exclude": ["node_modules"] diff --git a/yarn.lock b/yarn.lock index f2f3d1f2..4931b625 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,18 +10,18 @@ "@babel/highlight" "^7.10.4" "@babel/core@^7.7.5": - version "7.11.4" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.11.4.tgz#4301dfdfafa01eeb97f1896c5501a3f0655d4229" - integrity sha512-5deljj5HlqRXN+5oJTY7Zs37iH3z3b++KjiKtIsJy1NrjOOVSEaJHEetLBhyu0aQOSNNZ/0IuEAan9GzRuDXHg== + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.11.5.tgz#6ad96e2f71899ea3f9b651f0a911e85205d1ff6d" + integrity sha512-fsEANVOcZHzrsV6dMVWqpSeXClq3lNbYrfFGme6DE25FQWe7pyeYpXyx9guqUnpy466JLzZ8z4uwSr2iv60V5Q== dependencies: "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.4" + "@babel/generator" "^7.11.5" "@babel/helper-module-transforms" "^7.11.0" "@babel/helpers" "^7.10.4" - "@babel/parser" "^7.11.4" + "@babel/parser" "^7.11.5" "@babel/template" "^7.10.4" - "@babel/traverse" "^7.11.0" - "@babel/types" "^7.11.0" + "@babel/traverse" "^7.11.5" + "@babel/types" "^7.11.5" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.1" @@ -29,16 +29,16 @@ lodash "^4.17.19" resolve "^1.3.2" semver "^5.4.1" - source-map "^0.5.0" + source-map "^0.6.1" -"@babel/generator@^7.11.0", "@babel/generator@^7.11.4": - version "7.11.4" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.11.4.tgz#1ec7eec00defba5d6f83e50e3ee72ae2fee482be" - integrity sha512-Rn26vueFx0eOoz7iifCN2UHT6rGtnkSGWSoDRIy8jZN3B91PzeSULbswfLoOWuTuAcNwpG/mxy+uCTDnZ9Mp1g== +"@babel/generator@^7.11.5": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.11.5.tgz#a5582773425a468e4ba269d9a1f701fbca6a7a82" + integrity sha512-9UqHWJ4IwRTy4l0o8gq2ef8ws8UPzvtMkVKjTLAiRmza9p9V6Z+OfuNd9fB1j5Q67F+dVJtPC2sZXI8NM9br4g== dependencies: - "@babel/types" "^7.11.0" + "@babel/types" "^7.11.5" jsesc "^2.5.1" - source-map "^0.5.0" + source-map "^0.6.1" "@babel/helper-function-name@^7.10.4": version "7.10.4" @@ -138,10 +138,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.10.4", "@babel/parser@^7.11.0", "@babel/parser@^7.11.4": - version "7.11.4" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.11.4.tgz#6fa1a118b8b0d80d0267b719213dc947e88cc0ca" - integrity sha512-MggwidiH+E9j5Sh8pbrX5sJvMcsqS5o+7iB42M9/k0CD63MjYbdP4nhSh7uB5wnv2/RVzTZFTxzF/kIa5mrCqA== +"@babel/parser@^7.10.4", "@babel/parser@^7.11.5": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.11.5.tgz#c7ff6303df71080ec7a4f5b8c003c58f1cf51037" + integrity sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q== "@babel/template@^7.10.4": version "7.10.4" @@ -152,25 +152,25 @@ "@babel/parser" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/traverse@^7.10.4", "@babel/traverse@^7.11.0": - version "7.11.0" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz#9b996ce1b98f53f7c3e4175115605d56ed07dd24" - integrity sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg== +"@babel/traverse@^7.10.4", "@babel/traverse@^7.11.5": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.5.tgz#be777b93b518eb6d76ee2e1ea1d143daa11e61c3" + integrity sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ== dependencies: "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.0" + "@babel/generator" "^7.11.5" "@babel/helper-function-name" "^7.10.4" "@babel/helper-split-export-declaration" "^7.11.0" - "@babel/parser" "^7.11.0" - "@babel/types" "^7.11.0" + "@babel/parser" "^7.11.5" + "@babel/types" "^7.11.5" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.19" -"@babel/types@^7.10.4", "@babel/types@^7.11.0": - version "7.11.0" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz#2ae6bf1ba9ae8c3c43824e5861269871b206e90d" - integrity sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA== +"@babel/types@^7.10.4", "@babel/types@^7.11.0", "@babel/types@^7.11.5": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz#d9de577d01252d77c6800cee039ee64faf75662d" + integrity sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q== dependencies: "@babel/helper-validator-identifier" "^7.10.4" lodash "^4.17.19" @@ -183,6 +183,16 @@ dependencies: arrify "^1.0.1" +"@eslint/eslintrc@^0.1.0": + version "0.1.0" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.0.tgz#3d1f19fb797d42fb1c85458c1c73541eeb1d9e76" + integrity sha512-bfL5365QSCmH6cPeFT7Ywclj8C7LiF7sO6mUGzZhtAMV7iID1Euq6740u/SRi4C80NOnVz/CEfK8/HO+nCAPJg== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + import-fresh "^3.2.1" + strip-json-comments "^3.1.1" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -206,12 +216,12 @@ resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== -"@node-rs/helper@^0.3.0": - version "0.3.0" - resolved "https://registry.npmjs.org/@node-rs/helper/-/helper-0.3.0.tgz#6ab53f3842086f56df92f4990dda642afba84f10" - integrity sha512-1p67WcdFAtz5jVGpzpqJL2W+JKmoW4jmPD2cIJOAU4U+Fl5G9QsoFTa07ctiNosSsjYqnvgyE0KWV75YdpDqDg== +"@node-rs/helper@^0.3.1": + version "0.3.1" + resolved "https://registry.npmjs.org/@node-rs/helper/-/helper-0.3.1.tgz#605d3fafb344a4b7b664236c9219ac3e1d72361b" + integrity sha512-3X6SJOcyFRYv1mjrjtSHiziJuzAsqaz2pFD3uuLxu4qJo4TH6H0gaUb1Bdxl/VtiDy2yR+eMyBOQFCvr/G2oLA== dependencies: - tslib "^2.0.0" + tslib "^2.0.1" "@nodelib/fs.scandir@2.1.3": version "2.1.3" @@ -239,51 +249,51 @@ resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== -"@swc-node/core-darwin@^0.4.2": - version "0.4.2" - resolved "https://registry.npmjs.org/@swc-node/core-darwin/-/core-darwin-0.4.2.tgz#d41fff560d20e1dc0bf1d077e3ad9eebe1f83862" - integrity sha512-PKQZs5Cd1zD0D8KUz2vKGfQET7b19TcIuJ3M5fffosCLo0PV39bi6jrRiILiyP8DPGhOHysOMYkpJh0suVV2uA== +"@swc-node/core-darwin@^0.6.1": + version "0.6.1" + resolved "https://registry.npmjs.org/@swc-node/core-darwin/-/core-darwin-0.6.1.tgz#ad20762202eb25523bb6bdde81e6f6cb5e909bd9" + integrity sha512-tMWzyFhq4zPKnqq7yhUknFQWIishokFMMaqaptXq8w3wnidOhUCr83GhVggnj8r8LnUtNB8pegEj17Kl/20qjQ== -"@swc-node/core-linux-musl@^0.6.0": - version "0.6.0" - resolved "https://registry.npmjs.org/@swc-node/core-linux-musl/-/core-linux-musl-0.6.0.tgz#b657cce9fc35dddbfb84305a52546d0ece327201" - integrity sha512-gOB6PxKs26ZWt4JHIvU4Le8Sht9Ob7t7n2UF7uWwsJ6idDE89SybvZBGfi8B/AKrP2ZQPMi1wNOJABTu8O7ZUw== +"@swc-node/core-linux-musl@^0.6.1": + version "0.6.1" + resolved "https://registry.npmjs.org/@swc-node/core-linux-musl/-/core-linux-musl-0.6.1.tgz#45e2e0b695f594df944f892e9f82a2ce77266bf1" + integrity sha512-VcQ1kdeRw1D8/uMk90wHSMJmT41Tex8iytuGKBl/bVOZ5wPD9wA3Sz5ieMgt4CNiUtVITTlpyTJuQgO526W7Ug== -"@swc-node/core-linux@^0.4.2": - version "0.4.2" - resolved "https://registry.npmjs.org/@swc-node/core-linux/-/core-linux-0.4.2.tgz#e65750d1bcde9f153ec5e2b418e9b56365c94691" - integrity sha512-DOgOclLtbAOA0oJqxjOk6ziYLJ9JeTE/b9GJQm2GLB2jZgMcAPp+u1Dj/cBWEek77YErMeLyD0sYxE4E56KpvQ== +"@swc-node/core-linux@^0.6.1": + version "0.6.1" + resolved "https://registry.npmjs.org/@swc-node/core-linux/-/core-linux-0.6.1.tgz#b17ad7a8dcc1e2c17951e871cfa5c535f1e74145" + integrity sha512-oeE50kwZ8FgmP+MDFWi5aQpi4A+xUsqBQphTI4Cth7IdNqWbCq+sKU1dMn5FBFpyrp9KxXX9zrWOZYN6dtlwcg== -"@swc-node/core-win32@^0.4.2": - version "0.4.2" - resolved "https://registry.npmjs.org/@swc-node/core-win32/-/core-win32-0.4.2.tgz#26b1a2a2c33da75d5e3b2876f61dfa81188fcfc8" - integrity sha512-GopRvIP/m2uJFaEEz3IuCEKBWjZxu/mW53fWjCrib5tU/Vs3bYu2oRs7u2n6XwCDMfPw8RNNutGtbYeWQWYklw== +"@swc-node/core-win32@^0.6.1": + version "0.6.1" + resolved "https://registry.npmjs.org/@swc-node/core-win32/-/core-win32-0.6.1.tgz#7c2c09a1d713166a7d86bc4ac74fdfdcd0901314" + integrity sha512-6t8wbrbrY28nLP0rPY6nAuz6wUAZRVwkuEVt6QDrz44eo8wJkPqmZBHhYubDgdiofnxHNOveR9i9sdH2Z7xOSg== -"@swc-node/core@^0.4.2": - version "0.4.2" - resolved "https://registry.npmjs.org/@swc-node/core/-/core-0.4.2.tgz#4216cb176fc352d7df09b1cf2579274931dc5644" - integrity sha512-32YeSm2Q4YClpKIA2ZJzdZDLvLcv3nyg6pyoupy/cJjLpojGg+Laigo310wkQaCt8Y0NYOOheI/o58TV8xtgYg== +"@swc-node/core@^0.6.1": + version "0.6.1" + resolved "https://registry.npmjs.org/@swc-node/core/-/core-0.6.1.tgz#f3cf3b669f094f6b3d6f78ade54224aaa62a3362" + integrity sha512-5DXGG7u1lawiZuqv2MDgKgXNpjXu08uxg89bPU8PJATGeP+EQtJDgHwM7uF1hmRM1wsOsIy4o1t10w6NUWKCxQ== dependencies: - "@node-rs/helper" "^0.3.0" + "@node-rs/helper" "^0.3.1" optionalDependencies: - "@swc-node/core-darwin" "^0.4.2" - "@swc-node/core-linux" "^0.4.2" - "@swc-node/core-win32" "^0.4.2" + "@swc-node/core-darwin" "^0.6.1" + "@swc-node/core-linux" "^0.6.1" + "@swc-node/core-win32" "^0.6.1" -"@swc-node/register@^0.4.2": - version "0.4.2" - resolved "https://registry.npmjs.org/@swc-node/register/-/register-0.4.2.tgz#5d07e1c16fca102a27490d3ec5eeafcdd22a8b33" - integrity sha512-F0kD0gOWu2t8br8UZeAfrUFvab7iLs678DoVQrDseqZWSNtqF43F7upQBBKlDRO+mVOCtwdRxGanm/R0Y+aqOA== +"@swc-node/register@^0.4.5": + version "0.4.5" + resolved "https://registry.npmjs.org/@swc-node/register/-/register-0.4.5.tgz#3e80f7f901cc45d17b88a6ee626016cafd30fbe5" + integrity sha512-7wY7i19u0ISfR4vmuzPh8XDwum31kiCvQEzkZ55EjzeUVBXhNm280as81jqsGiVW3dN2mlTHfQNLB9WwOLkEnQ== dependencies: - "@swc-node/core" "^0.4.2" - "@swc-node/sourcemap-support" "^0.1.7" + "@swc-node/core" "^0.6.1" + "@swc-node/sourcemap-support" "^0.1.8" debug "^4.1.1" pirates "^4.0.1" -"@swc-node/sourcemap-support@^0.1.7": - version "0.1.7" - resolved "https://registry.npmjs.org/@swc-node/sourcemap-support/-/sourcemap-support-0.1.7.tgz#2e9b94e0bb7735f4b1ce0f0a464325dd0ad25465" - integrity sha512-tC/h/JJi5WJuLbDbWt2aKFLyafUrbSnRwcpO89jmQIVtQUssbfoXGupoGrPThzCfrJyXUNNflWxl3SxIdCvPMA== +"@swc-node/sourcemap-support@^0.1.8": + version "0.1.8" + resolved "https://registry.npmjs.org/@swc-node/sourcemap-support/-/sourcemap-support-0.1.8.tgz#8cf74175ae5e3374612011e7e75c03637019db4c" + integrity sha512-AOH32yNN8UJh6Ayc+r3mnPdrjqqEjtXr9wsEiEhh3OqJWFXqkMOHC+18FYhHdTzGzhaYqUshQONjqOTC38yx7Q== dependencies: source-map-support "^0.5.19" @@ -299,11 +309,6 @@ resolved "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== -"@types/eslint-visitor-keys@^1.0.0": - version "1.0.0" - resolved "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" - integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== - "@types/glob@^7.1.1": version "7.1.3" resolved "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" @@ -321,9 +326,9 @@ rxjs "^6.4.0" "@types/json-schema@^7.0.3": - version "7.0.5" - resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" - integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ== + version "7.0.6" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" + integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== "@types/json5@^0.0.29": version "0.0.29" @@ -335,10 +340,10 @@ resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== -"@types/node@*", "@types/node@^14.6.0": - version "14.6.0" - resolved "https://registry.npmjs.org/@types/node/-/node-14.6.0.tgz#7d4411bf5157339337d7cff864d9ff45f177b499" - integrity sha512-mikldZQitV94akrc4sCcSjtJfsTKt4p+e/s0AGscVA6XArQ9kFclP+ZiYUMnq987rc6QlYxXv/EivqlfSLxpKA== +"@types/node@*", "@types/node@^14.6.2": + version "14.6.2" + resolved "https://registry.npmjs.org/@types/node/-/node-14.6.2.tgz#264b44c5a28dfa80198fc2f7b6d3c8a054b9491f" + integrity sha512-onlIwbaeqvZyniGPfdw/TEhKIh79pz66L1q06WUQqJLnAb6wbjvOtepLYTGHTqzdXgBYIE3ZdmqHDGsRsbBz7A== "@types/normalize-package-data@^2.4.0": version "2.4.0" @@ -357,92 +362,61 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.0.0.tgz#99349a501447fed91de18346705c0c65cf603bee" - integrity sha512-5e6q1TR7gS2P+8W2xndCu7gBh3BzmYEo70OyIdsmCmknHha/yNbz2vdevl+tP1uoaMOcrzg4gyrAijuV3DDBHA== +"@typescript-eslint/eslint-plugin@^4.0.1": + version "4.0.1" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.0.1.tgz#88bde9239e29d688315718552cf80a3490491017" + integrity sha512-pQZtXupCn11O4AwpYVUX4PDFfmIJl90ZgrEBg0CEcqlwvPiG0uY81fimr1oMFblZnpKAq6prrT9a59pj1x58rw== dependencies: - "@typescript-eslint/experimental-utils" "4.0.0" - "@typescript-eslint/scope-manager" "4.0.0" + "@typescript-eslint/experimental-utils" "4.0.1" + "@typescript-eslint/scope-manager" "4.0.1" debug "^4.1.1" functional-red-black-tree "^1.0.1" regexpp "^3.0.0" semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@3.10.1": - version "3.10.1" - resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.10.1.tgz#e179ffc81a80ebcae2ea04e0332f8b251345a686" - integrity sha512-DewqIgscDzmAfd5nOGe4zm6Bl7PKtMG2Ad0KG8CUZAHlXfAKTF9Ol5PXhiMh39yRL2ChRH1cuuUGOcVyyrhQIw== +"@typescript-eslint/experimental-utils@4.0.1": + version "4.0.1" + resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.1.tgz#7d9a3ab6821ad5274dad2186c1aa0d93afd696eb" + integrity sha512-gAqOjLiHoED79iYTt3F4uSHrYmg/GPz/zGezdB0jAdr6S6gwNiR/j7cTZ8nREKVzMVKLd9G3xbg1sV9GClW3sw== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/types" "3.10.1" - "@typescript-eslint/typescript-estree" "3.10.1" + "@typescript-eslint/scope-manager" "4.0.1" + "@typescript-eslint/types" "4.0.1" + "@typescript-eslint/typescript-estree" "4.0.1" eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/experimental-utils@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.0.tgz#fbec21a3b5ab59127edb6ce2e139ed378cc50eb5" - integrity sha512-hbX6zR+a/vcpFVNJYN/Nbd7gmaMosDTxHEKcvmhWeWcq/0UDifrqmCfkkodbAKL46Fn4ekSBMTyq2zlNDzcQxw== +"@typescript-eslint/parser@^4.0.1": + version "4.0.1" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.0.1.tgz#73772080db7a7a4534a35d719e006f503e664dc3" + integrity sha512-1+qLmXHNAWSQ7RB6fdSQszAiA7JTwzakj5cNYjBTUmpH2cqilxMZEIV+DRKjVZs8NzP3ALmKexB0w/ExjcK9Iw== dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.0.0" - "@typescript-eslint/types" "4.0.0" - "@typescript-eslint/typescript-estree" "4.0.0" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - -"@typescript-eslint/parser@^3.10.1": - version "3.10.1" - resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.10.1.tgz#1883858e83e8b442627e1ac6f408925211155467" - integrity sha512-Ug1RcWcrJP02hmtaXVS3axPPTTPnZjupqhgj+NnZ6BCkwSImWk/283347+x9wN+lqOdK9Eo3vsyiyDHgsmiEJw== - dependencies: - "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "3.10.1" - "@typescript-eslint/types" "3.10.1" - "@typescript-eslint/typescript-estree" "3.10.1" - eslint-visitor-keys "^1.1.0" - -"@typescript-eslint/scope-manager@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.0.0.tgz#8c9e3b3b8cdf5a1fbe671d9fad73ff67bc027ea8" - integrity sha512-9gcWUPoWo7gk/+ZQPg7L1ySRmR5HLIy3Vu6/LfhQbuzIkGm6v2CGIjpVRISoDLFRovNRDImd4aP/sa8O4yIEBg== - dependencies: - "@typescript-eslint/types" "4.0.0" - "@typescript-eslint/visitor-keys" "4.0.0" - -"@typescript-eslint/types@3.10.1": - version "3.10.1" - resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.10.1.tgz#1d7463fa7c32d8a23ab508a803ca2fe26e758727" - integrity sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ== - -"@typescript-eslint/types@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.0.0.tgz#ec1f9fc06b8558a1d5afa6e337182d08beece7f5" - integrity sha512-bK+c2VLzznX2fUWLK6pFDv3cXGTp7nHIuBMq1B9klA+QCsqLHOOqe5TQReAQDl7DN2RfH+neweo0oC5hYlG7Rg== - -"@typescript-eslint/typescript-estree@3.10.1": - version "3.10.1" - resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.10.1.tgz#fd0061cc38add4fad45136d654408569f365b853" - integrity sha512-QbcXOuq6WYvnB3XPsZpIwztBoquEYLXh2MtwVU+kO8jgYCiv4G5xrSP/1wg4tkvrEE+esZVquIPX/dxPlePk1w== - dependencies: - "@typescript-eslint/types" "3.10.1" - "@typescript-eslint/visitor-keys" "3.10.1" + "@typescript-eslint/scope-manager" "4.0.1" + "@typescript-eslint/types" "4.0.1" + "@typescript-eslint/typescript-estree" "4.0.1" debug "^4.1.1" - glob "^7.1.6" - is-glob "^4.0.1" - lodash "^4.17.15" - semver "^7.3.2" - tsutils "^3.17.1" -"@typescript-eslint/typescript-estree@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.0.tgz#2244c63de2f2190bc5718eb0fb3fd2c437d42097" - integrity sha512-ewFMPi2pMLDNIXGMPdf8r7El2oPSZw9PEYB0j+WcpKd7AX2ARmajGa7RUHTukllWX2bj4vWX6JLE1Oih2BMokA== +"@typescript-eslint/scope-manager@4.0.1": + version "4.0.1" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.0.1.tgz#24d93c3000bdfcc5a157dc4d32b742405a8631b5" + integrity sha512-u3YEXVJ8jsj7QCJk3om0Y457fy2euEOkkzxIB/LKU3MdyI+FJ2gI0M4aKEaXzwCSfNDiZ13a3lDo5DVozc+XLQ== dependencies: - "@typescript-eslint/types" "4.0.0" - "@typescript-eslint/visitor-keys" "4.0.0" + "@typescript-eslint/types" "4.0.1" + "@typescript-eslint/visitor-keys" "4.0.1" + +"@typescript-eslint/types@4.0.1": + version "4.0.1" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.0.1.tgz#1cf72582f764931f085cb8230ff215980fe467b2" + integrity sha512-S+gD3fgbkZYW2rnbjugNMqibm9HpEjqZBZkTiI3PwbbNGWmAcxolWIUwZ0SKeG4Dy2ktpKKaI/6+HGYVH8Qrlg== + +"@typescript-eslint/typescript-estree@4.0.1": + version "4.0.1" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.1.tgz#29a43c7060641ec51c902d9f50ac7c5866ec479f" + integrity sha512-zGzleORFXrRWRJAMLTB2iJD1IZbCPkg4hsI8mGdpYlKaqzvKYSEWVAYh14eauaR+qIoZVWrXgYSXqLtTlxotiw== + dependencies: + "@typescript-eslint/types" "4.0.1" + "@typescript-eslint/visitor-keys" "4.0.1" debug "^4.1.1" globby "^11.0.1" is-glob "^4.0.1" @@ -450,19 +424,12 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/visitor-keys@3.10.1": - version "3.10.1" - resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.10.1.tgz#cd4274773e3eb63b2e870ac602274487ecd1e931" - integrity sha512-9JgC82AaQeglebjZMgYR5wgmfUdUc+EitGUUMW8u2nDckaeimzW+VsoLV6FoimPv2id3VQzfjwBxEMVz08ameQ== +"@typescript-eslint/visitor-keys@4.0.1": + version "4.0.1" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.1.tgz#d4e8de62775f2a6db71c7e8539633680039fdd6c" + integrity sha512-yBSqd6FjnTzbg5RUy9J+9kJEyQjTI34JdGMJz+9ttlJzLCnGkBikxw+N5n2VDcc3CesbIEJ0MnZc5uRYnrEnCw== dependencies: - eslint-visitor-keys "^1.1.0" - -"@typescript-eslint/visitor-keys@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.0.tgz#e2bbb69d98076d6a3f06abcb2048225a74362c33" - integrity sha512-sTouJbv6rjVJeTE4lpSBVYXq/u5K3gbB6LKt7ccFEZPTZB/VeQ0ssUz9q5Hx++sCqBbdF8PzrrgvEnicXAR6NQ== - dependencies: - "@typescript-eslint/types" "4.0.0" + "@typescript-eslint/types" "4.0.1" eslint-visitor-keys "^2.0.0" acorn-jsx@^5.2.0: @@ -493,7 +460,7 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv@^6.10.0, ajv@^6.10.2: +ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.4: version "6.12.4" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz#0614facc4522127fa713445c6bfd3ebd376e2234" integrity sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ== @@ -850,9 +817,9 @@ clean-yaml-object@^0.1.0: integrity sha1-Y/sRDcLOGoTcIfbZM0h20BCui2g= cli-boxes@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz#538ecae8f9c6ca508e3c3c95b453fe93cb4c168d" - integrity sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w== + version "2.2.1" + resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" + integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== cli-cursor@^3.1.0: version "3.1.0" @@ -879,10 +846,10 @@ cli-width@^3.0.0: resolved "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== -clipanion@^2.4.4: - version "2.4.4" - resolved "https://registry.npmjs.org/clipanion/-/clipanion-2.4.4.tgz#d70244c6f60feb3f4cbd509d2fcbe829fc619061" - integrity sha512-KjyCBz8xplftHjIK/nOqq/9b3hPlXbAAo/AxoITrO4yySpQ6a9QSJDAfOx9PfcRUHteeqbdNxZKSPfeFqQ7plg== +clipanion@^2.5.0: + version "2.5.0" + resolved "https://registry.npmjs.org/clipanion/-/clipanion-2.5.0.tgz#eb9c85a6b52a46979b7eb1e79534b23c44a52971" + integrity sha512-VYOMl0h/mZXQC2BWq7oBto1zY1SkPWUaJjt+cuIred1HrmrcX1I2N+LNyNoRy8Iwu9r6vUxJwS/tWLwhQW4tPw== cliui@^6.0.0: version "6.0.0" @@ -1351,12 +1318,13 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== -eslint@^7.7.0: - version "7.7.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-7.7.0.tgz#18beba51411927c4b64da0a8ceadefe4030d6073" - integrity sha512-1KUxLzos0ZVsyL81PnRN335nDtQ8/vZUD6uMtWbF+5zDtjKcsklIi78XoE0MVL93QvWTu+E5y44VyyCsOMBrIg== +eslint@^7.8.0: + version "7.8.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-7.8.0.tgz#9a3e2e6e4d0a3f8c42686073c25ebf2e91443e8a" + integrity sha512-qgtVyLZqKd2ZXWnLQA4NtVbOyH56zivOAdBFWE54RFkSZjokzNrcP4Z0eVWsZ+84ByXv+jL9k/wE1ENYe8xRFw== dependencies: "@babel/code-frame" "^7.0.0" + "@eslint/eslintrc" "^0.1.0" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -1366,7 +1334,7 @@ eslint@^7.7.0: eslint-scope "^5.1.0" eslint-utils "^2.1.0" eslint-visitor-keys "^1.3.0" - espree "^7.2.0" + espree "^7.3.0" esquery "^1.2.0" esutils "^2.0.2" file-entry-cache "^5.0.1" @@ -1393,7 +1361,7 @@ eslint@^7.7.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^7.2.0: +espree@^7.3.0: version "7.3.0" resolved "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz#dc30437cf67947cf576121ebd780f15eeac72348" integrity sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw== @@ -1415,18 +1383,18 @@ esquery@^1.2.0: estraverse "^5.1.0" esrecurse@^4.1.0: - version "4.2.1" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" - integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== + version "4.3.0" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== dependencies: - estraverse "^4.1.0" + estraverse "^5.2.0" -estraverse@^4.1.0, estraverse@^4.1.1: +estraverse@^4.1.1: version "4.3.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -estraverse@^5.1.0: +estraverse@^5.1.0, estraverse@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== @@ -2374,9 +2342,9 @@ md5-hex@^3.0.1: blueimp-md5 "^2.10.0" mem@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/mem/-/mem-6.1.0.tgz#846eca0bd4708a8f04b9c3f3cd769e194ae63c5c" - integrity sha512-RlbnLQgRHk5lwqTtpEkBTQ2ll/CG/iB+J4Hy2Wh97PjgZgXgWJWrFF+XXujh3UUVLvR4OOTgZzcWMMwnehlEUg== + version "6.1.1" + resolved "https://registry.npmjs.org/mem/-/mem-6.1.1.tgz#ea110c2ebc079eca3022e6b08c85a795e77f6318" + integrity sha512-Ci6bIfq/UgcxPTYa8dQQ5FY3BzKkT894bwXWXxC/zqs0XgMO2cT20CGkOqda7gZNkmK5VP4x89IGZ6K7hfbn3Q== dependencies: map-age-cleaner "^0.1.3" mimic-fn "^3.0.0" @@ -3224,11 +3192,6 @@ source-map-support@^0.5.17, source-map-support@^0.5.19: buffer-from "^1.0.0" source-map "^0.6.0" -source-map@^0.5.0: - version "0.5.7" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - source-map@^0.6.0, source-map@^0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -3376,7 +3339,7 @@ strip-final-newline@^2.0.0: resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-json-comments@^3.1.0: +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -3405,9 +3368,9 @@ supports-color@^5.3.0: has-flag "^3.0.0" supports-color@^7.1.0: - version "7.1.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" - integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + version "7.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" @@ -3515,7 +3478,7 @@ tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== -tslib@^2.0.0, tslib@^2.0.1: +tslib@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz#410eb0d113e5b6356490eec749603725b021b43e" integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ== @@ -3593,9 +3556,9 @@ update-notifier@^4.1.1: xdg-basedir "^4.0.0" uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + version "4.4.0" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602" + integrity sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g== dependencies: punycode "^2.1.0"