From 3565fccdb619749b7e6cb297dcf16e3c55cf6e0d Mon Sep 17 00:00:00 2001 From: LongYinan Date: Thu, 6 Jan 2022 15:56:14 +0800 Subject: [PATCH] fix(napi-derive): should throw rather than panic if object mismatched --- crates/backend/src/codegen/struct.rs | 14 ++++++++++++-- examples/napi/__test__/typegen.spec.ts.md | 4 ++++ examples/napi/__test__/typegen.spec.ts.snap | Bin 2226 -> 2252 bytes examples/napi/__test__/values.spec.ts | 10 ++++++++++ examples/napi/index.d.ts | 4 ++++ examples/napi/src/object.rs | 10 ++++++++++ 6 files changed, 40 insertions(+), 2 deletions(-) diff --git a/crates/backend/src/codegen/struct.rs b/crates/backend/src/codegen/struct.rs index 06302a43..4e1ef477 100644 --- a/crates/backend/src/codegen/struct.rs +++ b/crates/backend/src/codegen/struct.rs @@ -322,7 +322,12 @@ impl NapiStruct { if is_optional_field { obj_field_getters.push(quote! { let #ident: #ty = obj.get(#field_js_name)?; }); } 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) => { @@ -339,7 +344,12 @@ impl NapiStruct { if is_optional_field { obj_field_getters.push(quote! { let arg #i: #ty = obj.get(#field_js_name)?; }); } 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), + ))?; + }); } } } diff --git a/examples/napi/__test__/typegen.spec.ts.md b/examples/napi/__test__/typegen.spec.ts.md index 23907a13..55b92aca 100644 --- a/examples/napi/__test__/typegen.spec.ts.md +++ b/examples/napi/__test__/typegen.spec.ts.md @@ -94,6 +94,10 @@ Generated by [AVA](https://avajs.dev). b: number␊ }␊ export function fnReceivedAliased(s: AliasedStruct, e: ALIAS): void␊ + export interface StrictObject {␊ + name: string␊ + }␊ + export function receiveStrictObject(strictObject: StrictObject): void␊ export function asyncPlus100(p: Promise): Promise␊ /** This is an interface for package.json */␊ export interface PackageJson {␊ diff --git a/examples/napi/__test__/typegen.spec.ts.snap b/examples/napi/__test__/typegen.spec.ts.snap index 1730c62434e900eddab09ecfec8a637398460cf7..36b7e036f4ba6bce14b14f0ea6f9d04b6bbe1ede 100644 GIT binary patch literal 2252 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 AZ~y=R diff --git a/examples/napi/__test__/values.spec.ts b/examples/napi/__test__/values.spec.ts index 2745b850..395f0719 100644 --- a/examples/napi/__test__/values.spec.ts +++ b/examples/napi/__test__/values.spec.ts @@ -72,6 +72,7 @@ import { Dog, Bird, Assets, + receiveStrictObject, } from '../' test('export const', (t) => { @@ -245,6 +246,15 @@ test('option object', (t) => { 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) => { const a: ALIAS = ALIAS.A const b: AliasedStruct = { diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index 3453c31c..cd2e9b02 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -84,6 +84,10 @@ export interface AliasedStruct { b: number } export function fnReceivedAliased(s: AliasedStruct, e: ALIAS): void +export interface StrictObject { + name: string +} +export function receiveStrictObject(strictObject: StrictObject): void export function asyncPlus100(p: Promise): Promise /** This is an interface for package.json */ export interface PackageJson { diff --git a/examples/napi/src/object.rs b/examples/napi/src/object.rs index 741c74cf..6ae0fa5b 100644 --- a/examples/napi/src/object.rs +++ b/examples/napi/src/object.rs @@ -59,3 +59,13 @@ pub struct StructContainsAliasedEnum { fn fn_received_aliased(mut s: StructContainsAliasedEnum, e: AliasedEnum) { 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"); +}