fix(napi-derive): should throw rather than panic if object mismatched

This commit is contained in:
LongYinan 2022-01-06 15:56:14 +08:00
parent b39802a2ca
commit 3565fccdb6
No known key found for this signature in database
GPG key ID: C3666B7FC82ADAD7
6 changed files with 40 additions and 2 deletions

View file

@ -322,7 +322,12 @@ impl NapiStruct {
if is_optional_field { if is_optional_field {
obj_field_getters.push(quote! { let #ident: #ty = obj.get(#field_js_name)?; }); obj_field_getters.push(quote! { let #ident: #ty = obj.get(#field_js_name)?; });
} else { } else {
obj_field_getters.push(quote! { let #ident: #ty = obj.get(#field_js_name)?.expect(&format!("Field {} should exist", #field_js_name)); }); obj_field_getters.push(quote! {
let #ident: #ty = obj.get(#field_js_name)?.ok_or_else(|| napi::bindgen_prelude::Error::new(
napi::bindgen_prelude::Status::InvalidArg,
format!("Missing field `{}`", #field_js_name),
))?;
});
} }
} }
syn::Member::Unnamed(i) => { syn::Member::Unnamed(i) => {
@ -339,7 +344,12 @@ impl NapiStruct {
if is_optional_field { if is_optional_field {
obj_field_getters.push(quote! { let arg #i: #ty = obj.get(#field_js_name)?; }); obj_field_getters.push(quote! { let arg #i: #ty = obj.get(#field_js_name)?; });
} else { } else {
obj_field_getters.push(quote! { let arg #i: #ty = obj.get(#field_js_name)?.expect(&format!("Field {} should exist", #field_js_name)); }); obj_field_getters.push(quote! {
let arg #i: #ty = obj.get(#field_js_name)?.ok_or_else(|| napi::bindgen_prelude::Error::new(
napi::bindgen_prelude::Status::InvalidArg,
format!("Missing field `{}`", #field_js_name),
))?;
});
} }
} }
} }

View file

@ -94,6 +94,10 @@ Generated by [AVA](https://avajs.dev).
b: number␊ b: number␊
}␊ }␊
export function fnReceivedAliased(s: AliasedStruct, e: ALIAS): void␊ export function fnReceivedAliased(s: AliasedStruct, e: ALIAS): void␊
export interface StrictObject {␊
name: string␊
}␊
export function receiveStrictObject(strictObject: StrictObject): void␊
export function asyncPlus100(p: Promise<number>): Promise<number> export function asyncPlus100(p: Promise<number>): Promise<number>
/** This is an interface for package.json */␊ /** This is an interface for package.json */␊
export interface PackageJson {␊ export interface PackageJson {␊

View file

@ -72,6 +72,7 @@ import {
Dog, Dog,
Bird, Bird,
Assets, Assets,
receiveStrictObject,
} from '../' } from '../'
test('export const', (t) => { test('export const', (t) => {
@ -245,6 +246,15 @@ test('option object', (t) => {
t.notThrows(() => receiveAllOptionalObject({})) t.notThrows(() => receiveAllOptionalObject({}))
}) })
test('should throw if object type is not matched', (t) => {
// @ts-expect-error
const err1 = t.throws(() => receiveStrictObject({ name: 1 }))
t.is(err1!.message, 'Failed to convert napi `string` into rust type `String`')
// @ts-expect-error
const err2 = t.throws(() => receiveStrictObject({ bar: 1 }))
t.is(err2!.message, 'Missing field `name`')
})
test('aliased rust struct and enum', (t) => { test('aliased rust struct and enum', (t) => {
const a: ALIAS = ALIAS.A const a: ALIAS = ALIAS.A
const b: AliasedStruct = { const b: AliasedStruct = {

View file

@ -84,6 +84,10 @@ export interface AliasedStruct {
b: number b: number
} }
export function fnReceivedAliased(s: AliasedStruct, e: ALIAS): void export function fnReceivedAliased(s: AliasedStruct, e: ALIAS): void
export interface StrictObject {
name: string
}
export function receiveStrictObject(strictObject: StrictObject): void
export function asyncPlus100(p: Promise<number>): Promise<number> export function asyncPlus100(p: Promise<number>): Promise<number>
/** This is an interface for package.json */ /** This is an interface for package.json */
export interface PackageJson { export interface PackageJson {

View file

@ -59,3 +59,13 @@ pub struct StructContainsAliasedEnum {
fn fn_received_aliased(mut s: StructContainsAliasedEnum, e: AliasedEnum) { fn fn_received_aliased(mut s: StructContainsAliasedEnum, e: AliasedEnum) {
s.a = e; s.a = e;
} }
#[napi(object)]
pub struct StrictObject {
pub name: String,
}
#[napi]
pub fn receive_strict_object(strict_object: StrictObject) {
assert_eq!(strict_object.name, "strict");
}