diff --git a/crates/backend/src/codegen/enum.rs b/crates/backend/src/codegen/enum.rs index 57aa2515..a69e299a 100644 --- a/crates/backend/src/codegen/enum.rs +++ b/crates/backend/src/codegen/enum.rs @@ -51,8 +51,9 @@ impl NapiEnum { unsafe fn validate( env: napi::bindgen_prelude::sys::napi_env, napi_val: napi::bindgen_prelude::sys::napi_value - ) -> napi::bindgen_prelude::Result<()> { - napi::bindgen_prelude::assert_type_of!(env, napi_val, napi::bindgen_prelude::ValueType::Number) + ) -> napi::bindgen_prelude::Result { + napi::bindgen_prelude::assert_type_of!(env, napi_val, napi::bindgen_prelude::ValueType::Number)?; + Ok(std::ptr::null_mut()) } } diff --git a/crates/backend/src/codegen/fn.rs b/crates/backend/src/codegen/fn.rs index 1a58b472..30d4178b 100644 --- a/crates/backend/src/codegen/fn.rs +++ b/crates/backend/src/codegen/fn.rs @@ -159,7 +159,10 @@ impl NapiFn { _ => { let type_check = if self.strict { quote! { - <#ty as napi::bindgen_prelude::ValidateNapiValue>::validate(env, cb.get_arg(#index))?; + let maybe_promise = <#ty as napi::bindgen_prelude::ValidateNapiValue>::validate(env, cb.get_arg(#index))?; + if !maybe_promise.is_null() { + return Ok(maybe_promise); + } } } else { quote! {} diff --git a/crates/napi/src/bindgen_runtime/js_values.rs b/crates/napi/src/bindgen_runtime/js_values.rs index a835621b..579e12bf 100644 --- a/crates/napi/src/bindgen_runtime/js_values.rs +++ b/crates/napi/src/bindgen_runtime/js_values.rs @@ -114,10 +114,13 @@ pub trait ValidateNapiValue: FromNapiValue + TypeName { /// # Safety /// /// this function called to validate whether napi value passed to rust is valid type - unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<()> { + unsafe fn validate( + env: sys::napi_env, + napi_val: sys::napi_value, + ) -> Result { let available_types = Self::type_of(); if available_types.is_empty() { - return Ok(()); + return Ok(ptr::null_mut()); } let mut result = -1; @@ -128,7 +131,7 @@ pub trait ValidateNapiValue: FromNapiValue + TypeName { let received_type = ValueType::from(result); if available_types.contains(&received_type) { - Ok(()) + Ok(ptr::null_mut()) } else { Err(Error::new( Status::InvalidArg, diff --git a/crates/napi/src/bindgen_runtime/js_values/array.rs b/crates/napi/src/bindgen_runtime/js_values/array.rs index 2b6c2137..30d19d44 100644 --- a/crates/napi/src/bindgen_runtime/js_values/array.rs +++ b/crates/napi/src/bindgen_runtime/js_values/array.rs @@ -257,7 +257,21 @@ impl ValidateNapiValue for Vec where T: FromNapiValue, { - fn type_of() -> Vec { - vec![ValueType::Object] + unsafe fn validate( + env: sys::napi_env, + napi_val: sys::napi_value, + ) -> Result { + let mut is_array = false; + check_status!( + unsafe { sys::napi_is_array(env, napi_val, &mut is_array) }, + "Failed to check given napi value is array" + )?; + if !is_array { + return Err(Error::new( + Status::InvalidArg, + "Expected an array".to_owned(), + )); + } + Ok(ptr::null_mut()) } } diff --git a/crates/napi/src/bindgen_runtime/js_values/arraybuffer.rs b/crates/napi/src/bindgen_runtime/js_values/arraybuffer.rs index 4f8eb901..ce092d31 100644 --- a/crates/napi/src/bindgen_runtime/js_values/arraybuffer.rs +++ b/crates/napi/src/bindgen_runtime/js_values/arraybuffer.rs @@ -6,7 +6,7 @@ use std::ptr; pub use crate::js_values::TypedArrayType; use crate::{check_status, sys, Error, Result, Status}; -use super::{FromNapiValue, ToNapiValue, TypeName}; +use super::{FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue}; macro_rules! impl_typed_array { ($name:ident, $rust_type:ident, $typed_array_type:expr) => { @@ -98,7 +98,7 @@ macro_rules! impl_typed_array { impl TypeName for $name { fn type_name() -> &'static str { - "TypedArray" + concat!("TypedArray<", stringify!($rust_type), ">") } fn value_type() -> crate::ValueType { @@ -106,6 +106,26 @@ macro_rules! impl_typed_array { } } + impl ValidateNapiValue for $name { + unsafe fn validate( + env: sys::napi_env, + napi_val: sys::napi_value, + ) -> Result<$crate::sys::napi_value> { + let mut is_typed_array = false; + check_status!( + unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typed_array) }, + "Failed to check if value is typed array" + )?; + if !is_typed_array { + return Err(Error::new( + Status::InvalidArg, + "Expected a TypedArray value".to_owned(), + )); + } + Ok(ptr::null_mut()) + } + } + impl FromNapiValue for $name { unsafe fn from_napi_value( env: napi_sys::napi_env, diff --git a/crates/napi/src/bindgen_runtime/js_values/bigint.rs b/crates/napi/src/bindgen_runtime/js_values/bigint.rs index 8a87764e..3149c2e9 100644 --- a/crates/napi/src/bindgen_runtime/js_values/bigint.rs +++ b/crates/napi/src/bindgen_runtime/js_values/bigint.rs @@ -12,7 +12,7 @@ use std::ptr; use crate::{check_status, sys}; -use super::{FromNapiValue, ToNapiValue, TypeName}; +use super::{FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue}; /// i64 is converted to `Number` #[repr(transparent)] @@ -38,6 +38,12 @@ impl TypeName for BigInt { } } +impl ValidateNapiValue for BigInt { + fn type_of() -> Vec { + vec![crate::ValueType::BigInt] + } +} + impl FromNapiValue for BigInt { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result { let mut word_count = 0usize; diff --git a/crates/napi/src/bindgen_runtime/js_values/buffer.rs b/crates/napi/src/bindgen_runtime/js_values/buffer.rs index db5233cd..c54347b3 100644 --- a/crates/napi/src/bindgen_runtime/js_values/buffer.rs +++ b/crates/napi/src/bindgen_runtime/js_values/buffer.rs @@ -140,7 +140,18 @@ impl ToNapiValue for Buffer { } impl ValidateNapiValue for Buffer { - fn type_of() -> Vec { - vec![ValueType::Object] + unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result { + let mut is_buffer = false; + check_status!( + unsafe { sys::napi_is_buffer(env, napi_val, &mut is_buffer) }, + "Failed to validate napi buffer" + )?; + if !is_buffer { + return Err(Error::new( + Status::InvalidArg, + "Expected a Buffer value".to_owned(), + )); + } + Ok(ptr::null_mut()) } } diff --git a/crates/napi/src/bindgen_runtime/js_values/date.rs b/crates/napi/src/bindgen_runtime/js_values/date.rs index 8188fcb6..a8b77994 100644 --- a/crates/napi/src/bindgen_runtime/js_values/date.rs +++ b/crates/napi/src/bindgen_runtime/js_values/date.rs @@ -1,6 +1,9 @@ -use crate::{bindgen_prelude::*, check_status, sys, ValueType}; +use std::ptr; + use chrono::{DateTime, NaiveDateTime, Utc}; +use crate::{bindgen_prelude::*, check_status, sys, ValueType}; + impl TypeName for DateTime { fn type_name() -> &'static str { "DateTime" @@ -12,8 +15,20 @@ impl TypeName for DateTime { } impl ValidateNapiValue for DateTime { - fn type_of() -> Vec { - vec![ValueType::Object] + unsafe fn validate( + env: sys::napi_env, + napi_val: sys::napi_value, + ) -> Result { + let mut is_date = false; + check_status!(unsafe { napi_sys::napi_is_date(env, napi_val, &mut is_date) })?; + if !is_date { + return Err(Error::new( + Status::InvalidArg, + "Expected a Date object".to_owned(), + )); + } + + Ok(ptr::null_mut()) } } diff --git a/crates/napi/src/bindgen_runtime/js_values/external.rs b/crates/napi/src/bindgen_runtime/js_values/external.rs index 4848cd91..eb0fb33e 100644 --- a/crates/napi/src/bindgen_runtime/js_values/external.rs +++ b/crates/napi/src/bindgen_runtime/js_values/external.rs @@ -5,7 +5,7 @@ use std::{ use crate::{check_status, Error, Status, TaggedObject}; -use super::{FromNapiValue, ToNapiValue}; +use super::{FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue}; pub struct External { obj: *mut TaggedObject, @@ -13,6 +13,22 @@ pub struct External { pub adjusted_size: i64, } +impl TypeName for External { + fn type_name() -> &'static str { + "External" + } + + fn value_type() -> crate::ValueType { + crate::ValueType::External + } +} + +impl ValidateNapiValue for External { + fn type_of() -> Vec { + vec![crate::ValueType::External] + } +} + impl External { pub fn new(value: T) -> Self { Self { diff --git a/crates/napi/src/bindgen_runtime/js_values/function.rs b/crates/napi/src/bindgen_runtime/js_values/function.rs index 17f75ff0..208251d5 100644 --- a/crates/napi/src/bindgen_runtime/js_values/function.rs +++ b/crates/napi/src/bindgen_runtime/js_values/function.rs @@ -1 +1,9 @@ +use super::ValidateNapiValue; + pub use crate::JsFunction; + +impl ValidateNapiValue for JsFunction { + fn type_of() -> Vec { + vec![crate::ValueType::Function] + } +} diff --git a/crates/napi/src/bindgen_runtime/js_values/map.rs b/crates/napi/src/bindgen_runtime/js_values/map.rs index c78e361c..91f6e8ea 100644 --- a/crates/napi/src/bindgen_runtime/js_values/map.rs +++ b/crates/napi/src/bindgen_runtime/js_values/map.rs @@ -13,6 +13,12 @@ impl TypeName for HashMap { } } +impl + Eq + Hash, V: FromNapiValue> ValidateNapiValue for HashMap { + fn type_of() -> Vec { + vec![crate::ValueType::Object] + } +} + impl ToNapiValue for HashMap where K: AsRef, diff --git a/crates/napi/src/bindgen_runtime/js_values/object.rs b/crates/napi/src/bindgen_runtime/js_values/object.rs index 04870e59..512ff5ae 100644 --- a/crates/napi/src/bindgen_runtime/js_values/object.rs +++ b/crates/napi/src/bindgen_runtime/js_values/object.rs @@ -88,3 +88,9 @@ impl TypeName for Object { ValueType::Object } } + +impl ValidateNapiValue for Object { + fn type_of() -> Vec { + vec![ValueType::Object] + } +} diff --git a/crates/napi/src/bindgen_runtime/js_values/promise.rs b/crates/napi/src/bindgen_runtime/js_values/promise.rs index 17bfcc4b..a843a536 100644 --- a/crates/napi/src/bindgen_runtime/js_values/promise.rs +++ b/crates/napi/src/bindgen_runtime/js_values/promise.rs @@ -8,12 +8,79 @@ use tokio::sync::oneshot::{channel, Receiver, Sender}; use crate::{check_status, Error, Result, Status}; -use super::FromNapiValue; +use super::{FromNapiValue, TypeName, ValidateNapiValue}; pub struct Promise { value: Pin>>>, } +impl TypeName for Promise { + fn type_name() -> &'static str { + "Promise" + } + + fn value_type() -> crate::ValueType { + crate::ValueType::Object + } +} + +impl ValidateNapiValue for Promise { + fn type_of() -> Vec { + vec![crate::ValueType::Object] + } + + unsafe fn validate( + env: crate::sys::napi_env, + napi_val: crate::sys::napi_value, + ) -> Result { + let mut is_promise = false; + check_status!( + unsafe { crate::sys::napi_is_promise(env, napi_val, &mut is_promise) }, + "Failed to check if value is promise" + )?; + if !is_promise { + let mut deferred = ptr::null_mut(); + let mut promise = ptr::null_mut(); + check_status!( + unsafe { crate::sys::napi_create_promise(env, &mut deferred, &mut promise) }, + "Failed to create promise" + )?; + let mut err = ptr::null_mut(); + let mut code = ptr::null_mut(); + let mut message = ptr::null_mut(); + check_status!( + unsafe { + crate::sys::napi_create_string_utf8( + env, + CStr::from_bytes_with_nul_unchecked(b"InvalidArg\0").as_ptr(), + 10, + &mut code, + ) + }, + "Failed to create error message" + )?; + check_status!( + unsafe { + crate::sys::napi_create_string_utf8( + env, + CStr::from_bytes_with_nul_unchecked(b"Expected Promise object\0").as_ptr(), + 23, + &mut message, + ) + }, + "Failed to create error message" + )?; + check_status!( + unsafe { crate::sys::napi_create_error(env, code, message, &mut err) }, + "Failed to create rejected error" + )?; + check_status!(unsafe { crate::sys::napi_reject_deferred(env, deferred, err) })?; + return Ok(promise); + } + Ok(ptr::null_mut()) + } +} + unsafe impl Send for Promise {} impl FromNapiValue for Promise { diff --git a/crates/napi/src/bindgen_runtime/js_values/string.rs b/crates/napi/src/bindgen_runtime/js_values/string.rs index 2af44beb..4ab329ac 100644 --- a/crates/napi/src/bindgen_runtime/js_values/string.rs +++ b/crates/napi/src/bindgen_runtime/js_values/string.rs @@ -16,6 +16,12 @@ impl TypeName for String { } } +impl ValidateNapiValue for String { + fn type_of() -> Vec { + vec![ValueType::String] + } +} + impl ToNapiValue for String { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result { let mut ptr = ptr::null_mut(); @@ -75,6 +81,12 @@ impl TypeName for &str { } } +impl ValidateNapiValue for &str { + fn type_of() -> Vec { + vec![ValueType::String] + } +} + impl FromNapiValue for &str { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result { let mut len = 0; @@ -134,6 +146,12 @@ impl ToNapiValue for &str { #[derive(Debug)] pub struct Utf16String(String); +impl ValidateNapiValue for Utf16String { + fn type_of() -> Vec { + vec![ValueType::String] + } +} + impl From for Utf16String { fn from(s: String) -> Self { Utf16String(s) @@ -227,6 +245,12 @@ pub mod latin1_string { #[derive(Debug)] pub struct Latin1String(String); + impl ValidateNapiValue for Latin1String { + fn type_of() -> Vec { + vec![ValueType::String] + } + } + impl From for Latin1String { fn from(s: String) -> Self { Latin1String(s) diff --git a/crates/napi/src/bindgen_runtime/js_values/symbol.rs b/crates/napi/src/bindgen_runtime/js_values/symbol.rs index 181f6f9c..9cba30ae 100644 --- a/crates/napi/src/bindgen_runtime/js_values/symbol.rs +++ b/crates/napi/src/bindgen_runtime/js_values/symbol.rs @@ -2,12 +2,28 @@ use std::{ffi::CString, ptr}; use crate::check_status; -use super::ToNapiValue; +use super::{FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue}; pub struct Symbol { desc: Option, } +impl TypeName for Symbol { + fn type_name() -> &'static str { + "Symbol" + } + + fn value_type() -> crate::ValueType { + crate::ValueType::Object + } +} + +impl ValidateNapiValue for Symbol { + fn type_of() -> Vec { + vec![crate::ValueType::Symbol] + } +} + impl Symbol { pub fn new(desc: String) -> Self { Self { desc: Some(desc) } @@ -48,3 +64,12 @@ impl ToNapiValue for Symbol { Ok(symbol_value) } } + +impl FromNapiValue for Symbol { + unsafe fn from_napi_value( + _env: napi_sys::napi_env, + _napi_val: napi_sys::napi_value, + ) -> crate::Result { + Ok(Self { desc: None }) + } +} diff --git a/crates/napi/src/js_values/date.rs b/crates/napi/src/js_values/date.rs index 2b6946c8..6856b1af 100644 --- a/crates/napi/src/js_values/date.rs +++ b/crates/napi/src/js_values/date.rs @@ -1,5 +1,10 @@ +use std::ptr; + use super::check_status; -use crate::{bindgen_runtime::TypeName, sys, Result, Value, ValueType}; +use crate::{ + bindgen_runtime::{TypeName, ValidateNapiValue}, + sys, Error, Result, Status, Value, ValueType, +}; pub struct JsDate(pub(crate) Value); @@ -13,6 +18,21 @@ impl TypeName for JsDate { } } +impl ValidateNapiValue for JsDate { + unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result { + let mut is_date = false; + check_status!(unsafe { napi_sys::napi_is_date(env, napi_val, &mut is_date) })?; + if !is_date { + return Err(Error::new( + Status::InvalidArg, + "Expected a Date object".to_owned(), + )); + } + + Ok(ptr::null_mut()) + } +} + impl JsDate { pub fn value_of(&self) -> Result { let mut timestamp: f64 = 0.0; diff --git a/crates/napi/src/js_values/mod.rs b/crates/napi/src/js_values/mod.rs index 0cb7ae21..0787e541 100644 --- a/crates/napi/src/js_values/mod.rs +++ b/crates/napi/src/js_values/mod.rs @@ -3,7 +3,8 @@ use std::ffi::CString; use std::ptr; use crate::{ - bindgen_runtime::TypeName, check_status, sys, type_of, Callback, Error, Result, Status, ValueType, + bindgen_runtime::{TypeName, ValidateNapiValue}, + check_status, sys, type_of, Callback, Error, Result, Status, ValueType, }; #[cfg(feature = "serde-json")] @@ -85,6 +86,12 @@ impl TypeName for JsSymbol { } } +impl ValidateNapiValue for JsSymbol { + fn type_of() -> Vec { + vec![ValueType::Symbol] + } +} + pub struct JsExternal(pub(crate) Value); impl TypeName for JsExternal { diff --git a/examples/napi/__test__/strict.spect.ts b/examples/napi/__test__/strict.spect.ts new file mode 100644 index 00000000..d469ae2a --- /dev/null +++ b/examples/napi/__test__/strict.spect.ts @@ -0,0 +1,168 @@ +import test from 'ava' + +import { + validateArray, + validateTypedArray, + validateBigint, + validateBuffer, + validateBoolean, + validateDate, + validateDateTime, + createExternal, + validateExternal, + validateFunction, + validateHashMap, + validatePromise, + validateString, + validateSymbol, + validateNull, + validateUndefined, +} from '../index' + +test('should validate array', (t) => { + t.is(validateArray([1, 2, 3]), 3) + // @ts-expect-error + t.throws(() => validateArray(1), { + message: 'Expected an array', + code: 'InvalidArg', + }) +}) + +test('should validate arraybuffer', (t) => { + t.is(validateTypedArray(new Uint8Array([1, 2, 3])), 3) + // @ts-expect-error + t.throws(() => validateTypedArray(1), { + code: 'InvalidArg', + message: 'Expected a TypedArray value', + }) +}) + +test('should validate BigInt', (t) => { + if (typeof BigInt === 'undefined') { + t.pass('BigInt is not supported') + } else { + const fx = BigInt(1024 * 1024 * 1024 * 1024) + t.is(validateBigint(fx), fx) + // @ts-expect-error + t.throws(() => validateBigint(1), { + code: 'InvalidArg', + message: 'Expect value to be BigInt, but received Number', + }) + } +}) + +test('should validate buffer', (t) => { + t.is(validateBuffer(Buffer.from('hello')), 5) + // @ts-expect-error + t.throws(() => validateBuffer(2), { + code: 'InvalidArg', + message: 'Expected a Buffer value', + }) +}) + +test('should validate boolean value', (t) => { + t.is(validateBoolean(true), false) + t.is(validateBoolean(false), true) + // @ts-expect-error + t.throws(() => validateBoolean(1), { + code: 'InvalidArg', + message: 'Expect value to be Boolean, but received Number', + }) +}) + +test('should validate date', (t) => { + if (Number(process.versions.napi) >= 5) { + return t.pass() + } + const fx = new Date('2016-12-24') + t.is(validateDate(new Date()), fx.valueOf()) + t.is(validateDateTime(fx), 1) + // @ts-expect-error + t.throws(() => validateDate(1), { + code: 'InvalidArg', + message: 'Expected a Date value', + }) + // @ts-expect-error + t.throws(() => validateDateTime(2), { + code: 'InvalidArg', + message: 'Expected a Date value', + }) +}) + +test('should validate External', (t) => { + const fx = createExternal(1) + t.is(validateExternal(fx), 1) + // @ts-expect-error + t.throws(() => validateExternal(1), { + code: 'InvalidArg', + message: 'Expect value to be External, but received Number', + }) +}) + +test('should validate function', (t) => { + t.is( + validateFunction(() => 1), + 4, + ) + // @ts-expect-error + t.throws(() => validateFunction(2), { + code: 'InvalidArg', + message: 'Expect value to be Function, but received Number', + }) +}) + +test('should validate Map', (t) => { + t.is(validateHashMap({ a: 1, b: 2 }), 2) + // @ts-expect-error + t.throws(() => validateHashMap(), { + code: 'InvalidArg', + message: 'Expect value to be Object, but received Undefined', + }) +}) + +test('should validate promise', async (t) => { + t.is(await validatePromise(Promise.resolve(1)), 2) + // @ts-expect-error + await t.throwsAsync(() => validatePromise(1), { + code: 'InvalidArg', + message: 'Expected Promise object', + }) +}) + +test('should validate string', (t) => { + t.is(validateString('hello'), 'hello!') + // @ts-expect-error + t.throws(() => validateString(1), { + code: 'InvalidArg', + message: 'Expect value to be String, but received Number', + }) +}) + +test('should validate symbol', (t) => { + t.notThrows(() => validateSymbol(Symbol())) + // @ts-expect-error + t.throws(() => validateSymbol(1), { + code: 'InvalidArg', + message: 'Expect value to be Symbol, but received Number', + }) +}) + +test('should validate null', (t) => { + t.notThrows(() => validateNull(null)) + // @ts-expect-error + t.throws(() => validateNull(1), { + code: 'InvalidArg', + message: 'Expect value to be Null, but received Number', + }) +}) + +test('should validate undefined', (t) => { + t.notThrows(() => validateUndefined(void 0)) + // @ts-expect-error + t.notThrows(() => validateUndefined()) + // @ts-expect-error + t.throws(() => validateUndefined(1), { + code: 'InvalidArg', + message: 'Expect value to be Undefined, but received Number', + }) +}) diff --git a/examples/napi/__test__/typegen.spec.ts.md b/examples/napi/__test__/typegen.spec.ts.md index f7f6738f..922e7ee0 100644 --- a/examples/napi/__test__/typegen.spec.ts.md +++ b/examples/napi/__test__/typegen.spec.ts.md @@ -82,6 +82,22 @@ Generated by [AVA](https://avajs.dev). export function createExternalString(content: string): ExternalObject␊ export function getExternal(external: ExternalObject): number␊ export function mutateExternal(external: ExternalObject, newVal: number): void␊ + export function validateArray(arr: Array): number␊ + export function validateBuffer(b: Buffer): number␊ + export function validateTypedArray(input: Uint8Array): number␊ + export function validateBigint(input: bigint): bigint␊ + export function validateBoolean(i: boolean): boolean␊ + export function validateDate(d: Date): number␊ + export function validateDateTime(d: Date): number␊ + export function validateExternal(e: ExternalObject): number␊ + export function validateFunction(cb: () => number): number␊ + export function validateHashMap(input: Record): number␊ + export function validateNull(i: null): boolean␊ + export function validateUndefined(i: undefined): boolean␊ + export function validateNumber(i: number): number␊ + export function validatePromise(p: Promise): Promise␊ + export function validateString(s: string): string␊ + export function validateSymbol(s: symbol): boolean␊ export function tsRename(a: { foo: number }): string[]␊ export function xxh64Alias(input: Buffer): bigint␊ export function getMapping(): Record␊ diff --git a/examples/napi/__test__/typegen.spec.ts.snap b/examples/napi/__test__/typegen.spec.ts.snap index 39d0b36c..d1341ed1 100644 Binary files a/examples/napi/__test__/typegen.spec.ts.snap and b/examples/napi/__test__/typegen.spec.ts.snap differ diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index 9a636c1b..b17d1384 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -72,6 +72,22 @@ export function createExternal(size: number): ExternalObject export function createExternalString(content: string): ExternalObject export function getExternal(external: ExternalObject): number export function mutateExternal(external: ExternalObject, newVal: number): void +export function validateArray(arr: Array): number +export function validateBuffer(b: Buffer): number +export function validateTypedArray(input: Uint8Array): number +export function validateBigint(input: bigint): bigint +export function validateBoolean(i: boolean): boolean +export function validateDate(d: Date): number +export function validateDateTime(d: Date): number +export function validateExternal(e: ExternalObject): number +export function validateFunction(cb: () => number): number +export function validateHashMap(input: Record): number +export function validateNull(i: null): boolean +export function validateUndefined(i: undefined): boolean +export function validateNumber(i: number): number +export function validatePromise(p: Promise): Promise +export function validateString(s: string): string +export function validateSymbol(s: symbol): boolean export function tsRename(a: { foo: number }): string[] export function xxh64Alias(input: Buffer): bigint export function getMapping(): Record diff --git a/examples/napi/src/fn_strict.rs b/examples/napi/src/fn_strict.rs new file mode 100644 index 00000000..2b2a9cf0 --- /dev/null +++ b/examples/napi/src/fn_strict.rs @@ -0,0 +1,89 @@ +use std::collections::HashMap; + +use chrono::{DateTime, Utc}; +use napi::{bindgen_prelude::*, JsSymbol, JsUnknown}; + +#[napi(strict)] +fn validate_array(arr: Vec) -> u32 { + arr.len() as u32 +} + +#[napi(strict)] +fn validate_buffer(b: Buffer) -> u32 { + b.len() as u32 +} + +#[napi(strict)] +fn validate_typed_array(input: Uint8Array) -> u32 { + input.len() as u32 +} + +#[napi(strict)] +fn validate_bigint(input: BigInt) -> i128 { + input.get_i128().0 +} + +#[napi(strict)] +fn validate_boolean(i: bool) -> bool { + !i +} + +#[napi(strict)] +fn validate_date(d: Date) -> Result { + d.value_of() +} + +#[napi(strict)] +fn validate_date_time(_d: DateTime) -> i64 { + 1 +} + +#[napi(strict)] +fn validate_external(e: External) -> u32 { + *e +} + +#[napi(strict, ts_args_type = "cb: () => number")] +fn validate_function(cb: JsFunction) -> Result { + Ok( + cb.call::(None, &[])? + .coerce_to_number()? + .get_uint32()? + + 3, + ) +} + +#[napi(strict)] +fn validate_hash_map(input: HashMap) -> u32 { + input.len() as u32 +} + +#[napi(strict)] +fn validate_null(_i: Null) -> bool { + true +} + +#[napi(strict)] +fn validate_undefined(_i: Undefined) -> bool { + true +} + +#[napi(strict)] +fn validate_number(i: f64) -> f64 { + i + 1.0 +} + +#[napi(strict)] +async fn validate_promise(p: Promise) -> Result { + Ok(p.await? + 1) +} + +#[napi(strict)] +fn validate_string(s: String) -> String { + s + "!" +} + +#[napi(strict)] +fn validate_symbol(_s: JsSymbol) -> bool { + true +} diff --git a/examples/napi/src/lib.rs b/examples/napi/src/lib.rs index 98005952..b6baf3e7 100644 --- a/examples/napi/src/lib.rs +++ b/examples/napi/src/lib.rs @@ -23,6 +23,7 @@ mod either; mod r#enum; mod error; mod external; +mod fn_strict; mod fn_ts_override; mod js_mod; mod map;