Merge pull request #1223 from napi-rs/strict-check-optional
fix(napi): validate fn for Option<T>
This commit is contained in:
commit
1ac7fcf2ce
7 changed files with 50 additions and 2 deletions
|
@ -74,6 +74,8 @@ impl TypeName for JsUnknown {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ValidateNapiValue for JsUnknown {}
|
||||||
|
|
||||||
impl<T: NapiRaw> ToNapiValue for T {
|
impl<T: NapiRaw> ToNapiValue for T {
|
||||||
unsafe fn to_napi_value(_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
|
unsafe fn to_napi_value(_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
|
||||||
Ok(unsafe { NapiRaw::raw(&val) })
|
Ok(unsafe { NapiRaw::raw(&val) })
|
||||||
|
@ -158,6 +160,32 @@ impl<T: TypeName> TypeName for Option<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: ValidateNapiValue> ValidateNapiValue for Option<T> {
|
||||||
|
unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
|
||||||
|
let mut result = -1;
|
||||||
|
check_status!(
|
||||||
|
unsafe { sys::napi_typeof(env, napi_val, &mut result) },
|
||||||
|
"Failed to detect napi value type",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let received_type = ValueType::from(result);
|
||||||
|
if received_type == ValueType::Null {
|
||||||
|
Ok(ptr::null_mut())
|
||||||
|
} else if let Ok(validate_ret) = unsafe { T::validate(env, napi_val) } {
|
||||||
|
Ok(validate_ret)
|
||||||
|
} else {
|
||||||
|
Err(Error::new(
|
||||||
|
Status::InvalidArg,
|
||||||
|
format!(
|
||||||
|
"Expect value to be Option<{}>, but received {}",
|
||||||
|
T::value_type(),
|
||||||
|
received_type
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> FromNapiValue for Option<T>
|
impl<T> FromNapiValue for Option<T>
|
||||||
where
|
where
|
||||||
T: FromNapiValue,
|
T: FromNapiValue,
|
||||||
|
|
|
@ -56,7 +56,6 @@ impl ValidateNapiValue for Undefined {}
|
||||||
|
|
||||||
impl FromNapiValue for Undefined {
|
impl FromNapiValue for Undefined {
|
||||||
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
|
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
|
||||||
// TODO: with typecheck
|
|
||||||
match type_of!(env, napi_val) {
|
match type_of!(env, napi_val) {
|
||||||
Ok(ValueType::Undefined) => Ok(()),
|
Ok(ValueType::Undefined) => Ok(()),
|
||||||
_ => Err(Error::new(
|
_ => Err(Error::new(
|
||||||
|
@ -73,7 +72,7 @@ impl ToNapiValue for Undefined {
|
||||||
|
|
||||||
check_status!(
|
check_status!(
|
||||||
unsafe { sys::napi_get_undefined(env, &mut ret) },
|
unsafe { sys::napi_get_undefined(env, &mut ret) },
|
||||||
"Failed to create napi null value"
|
"Failed to create napi undefined value"
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
|
|
|
@ -19,6 +19,7 @@ import {
|
||||||
validateUndefined,
|
validateUndefined,
|
||||||
returnUndefinedIfInvalid,
|
returnUndefinedIfInvalid,
|
||||||
returnUndefinedIfInvalidPromise,
|
returnUndefinedIfInvalidPromise,
|
||||||
|
validateOptional,
|
||||||
} from '../index'
|
} from '../index'
|
||||||
|
|
||||||
test('should validate array', (t) => {
|
test('should validate array', (t) => {
|
||||||
|
@ -180,3 +181,16 @@ test('should return Promise.reject() if arg is not Promise', async (t) => {
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
await t.throwsAsync(() => returnUndefinedIfInvalidPromise(1))
|
await t.throwsAsync(() => returnUndefinedIfInvalidPromise(1))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('should validate Option<T>', (t) => {
|
||||||
|
t.is(validateOptional(null, null), false)
|
||||||
|
t.is(validateOptional(null, false), false)
|
||||||
|
t.is(validateOptional('1', false), true)
|
||||||
|
t.is(validateOptional(null, true), true)
|
||||||
|
// @ts-expect-error
|
||||||
|
t.throws(() => validateOptional(1, null))
|
||||||
|
// @ts-expect-error
|
||||||
|
t.throws(() => validateOptional(null, 2))
|
||||||
|
// @ts-expect-error
|
||||||
|
t.throws(() => validateOptional(1, 2))
|
||||||
|
})
|
||||||
|
|
|
@ -110,6 +110,7 @@ Generated by [AVA](https://avajs.dev).
|
||||||
export function validatePromise(p: Promise<number>): Promise<number>␊
|
export function validatePromise(p: Promise<number>): Promise<number>␊
|
||||||
export function validateString(s: string): string␊
|
export function validateString(s: string): string␊
|
||||||
export function validateSymbol(s: symbol): boolean␊
|
export function validateSymbol(s: symbol): boolean␊
|
||||||
|
export function validateOptional(input1?: string | undefined | null, input2?: boolean | undefined | null): boolean␊
|
||||||
export function returnUndefinedIfInvalid(input: boolean): boolean␊
|
export function returnUndefinedIfInvalid(input: boolean): boolean␊
|
||||||
export function returnUndefinedIfInvalidPromise(input: Promise<boolean>): Promise<boolean>␊
|
export function returnUndefinedIfInvalidPromise(input: Promise<boolean>): Promise<boolean>␊
|
||||||
export function tsRename(a: { foo: number }): string[]␊
|
export function tsRename(a: { foo: number }): string[]␊
|
||||||
|
|
Binary file not shown.
1
examples/napi/index.d.ts
vendored
1
examples/napi/index.d.ts
vendored
|
@ -100,6 +100,7 @@ export function validateNumber(i: number): number
|
||||||
export function validatePromise(p: Promise<number>): Promise<number>
|
export function validatePromise(p: Promise<number>): Promise<number>
|
||||||
export function validateString(s: string): string
|
export function validateString(s: string): string
|
||||||
export function validateSymbol(s: symbol): boolean
|
export function validateSymbol(s: symbol): boolean
|
||||||
|
export function validateOptional(input1?: string | undefined | null, input2?: boolean | undefined | null): boolean
|
||||||
export function returnUndefinedIfInvalid(input: boolean): boolean
|
export function returnUndefinedIfInvalid(input: boolean): boolean
|
||||||
export function returnUndefinedIfInvalidPromise(input: Promise<boolean>): Promise<boolean>
|
export function returnUndefinedIfInvalidPromise(input: Promise<boolean>): Promise<boolean>
|
||||||
export function tsRename(a: { foo: number }): string[]
|
export function tsRename(a: { foo: number }): string[]
|
||||||
|
|
|
@ -88,6 +88,11 @@ fn validate_symbol(_s: JsSymbol) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[napi(strict)]
|
||||||
|
fn validate_optional(input1: Option<String>, input2: Option<bool>) -> bool {
|
||||||
|
input1.is_some() || input2.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
#[napi(return_if_invalid)]
|
#[napi(return_if_invalid)]
|
||||||
fn return_undefined_if_invalid(input: bool) -> bool {
|
fn return_undefined_if_invalid(input: bool) -> bool {
|
||||||
!input
|
!input
|
||||||
|
|
Loading…
Reference in a new issue