From d58e488fa210d83e8cac814ff207403d51a532ab Mon Sep 17 00:00:00 2001 From: LongYinan Date: Thu, 2 Dec 2021 15:46:20 +0800 Subject: [PATCH 1/4] fix(cli): missing exported enum --- cli/src/build.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cli/src/build.ts b/cli/src/build.ts index 1d512310..51f66f97 100644 --- a/cli/src/build.ts +++ b/cli/src/build.ts @@ -383,6 +383,9 @@ export class ExternalObject { dts += indentLines(`}`, nest) + '\n' break case 'enum': + if (!nested) { + idents.push(def.name) + } dts += indentLines(`${def.js_doc}export enum ${def.name} {`, nest) + '\n' dts += indentLines(def.def, nest + 2) + '\n' From 6d4b4af36f9c37ed1cff694f2a267668a1b843de Mon Sep 17 00:00:00 2001 From: LongYinan Date: Thu, 2 Dec 2021 15:47:59 +0800 Subject: [PATCH 2/4] fix(napi-derive-backend): do not unwrap Option value in object getter if the type of field is Option --- crates/backend/src/codegen/struct.rs | 26 ++++++++++++++++-- .../src/bindgen_runtime/js_values/object.rs | 2 +- examples/napi/__test__/typegen.spec.ts.md | 5 ++++ examples/napi/__test__/typegen.spec.ts.snap | Bin 1831 -> 1873 bytes examples/napi/__test__/values.spec.ts | 6 ++++ examples/napi/index.d.ts | 5 ++++ examples/napi/src/object.rs | 15 ++++++++++ 7 files changed, 55 insertions(+), 4 deletions(-) diff --git a/crates/backend/src/codegen/struct.rs b/crates/backend/src/codegen/struct.rs index dc2efb75..07718f4a 100644 --- a/crates/backend/src/codegen/struct.rs +++ b/crates/backend/src/codegen/struct.rs @@ -239,17 +239,37 @@ impl NapiStruct { for field in self.fields.iter() { let field_js_name = &field.js_name; let ty = &field.ty; - + let is_optional_field = if let syn::Type::Path(syn::TypePath { + path: syn::Path { segments, .. }, + .. + }) = &ty + { + if let Some(last_path) = segments.last() { + last_path.ident.to_string() == "Option" + } else { + false + } + } else { + false + }; match &field.name { syn::Member::Named(ident) => { field_destructions.push(quote! { #ident }); obj_field_setters.push(quote! { obj.set(#field_js_name, #ident)?; }); - obj_field_getters.push(quote! { let #ident: #ty = obj.get(#field_js_name)?.expect(&format!("Field {} should exist", #field_js_name)); }); + 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)); }); + } } syn::Member::Unnamed(i) => { field_destructions.push(quote! { arg#i }); obj_field_setters.push(quote! { obj.set(#field_js_name, arg#1)?; }); - obj_field_getters.push(quote! { let arg#i: #ty = obj.get(#field_js_name)?.expect(&format!("Field {} should exist", #field_js_name)); }); + 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)); }); + } } } } diff --git a/crates/napi/src/bindgen_runtime/js_values/object.rs b/crates/napi/src/bindgen_runtime/js_values/object.rs index ef0b4d94..04870e59 100644 --- a/crates/napi/src/bindgen_runtime/js_values/object.rs +++ b/crates/napi/src/bindgen_runtime/js_values/object.rs @@ -35,7 +35,7 @@ impl Object { let ty = type_of!(self.0.env, ret)?; - Ok(if ty == ValueType::Undefined { + Ok(if ty == ValueType::Undefined || ty == ValueType::Null { None } else { Some(V::from_napi_value(self.0.env, ret)?) diff --git a/examples/napi/__test__/typegen.spec.ts.md b/examples/napi/__test__/typegen.spec.ts.md index a098885d..546498dd 100644 --- a/examples/napi/__test__/typegen.spec.ts.md +++ b/examples/napi/__test__/typegen.spec.ts.md @@ -73,6 +73,11 @@ Generated by [AVA](https://avajs.dev). export function getGlobal(): typeof global␊ export function getUndefined(): void␊ export function getNull(): JsNull␊ + export interface AllOptionalObject {␊ + name?: string | undefined | null␊ + age?: number | undefined | null␊ + }␊ + export function receiveAllOptionalObject(obj?: AllOptionalObject | undefined | null): 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 f674e93d429ec6229f522a7a04a060373fbe9982..8852cae6e3ea2a768385a88b906727190f2a3f7f 100644 GIT binary patch literal 1873 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 { @@ -202,6 +203,11 @@ test('function ts type override', (t) => { t.deepEqual(tsRename({ foo: 1, bar: 2, baz: 2 }), ['foo', 'bar', 'baz']) }) +test('option object', (t) => { + t.notThrows(() => receiveAllOptionalObject()) + t.notThrows(() => receiveAllOptionalObject({})) +}) + test('serde-json', (t) => { const packageJson = readPackageJson() t.is(packageJson.name, 'napi-rs') diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index f514c30d..216febe4 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -63,6 +63,11 @@ export function createObj(): object export function getGlobal(): typeof global export function getUndefined(): void export function getNull(): JsNull +export interface AllOptionalObject { + name?: string | undefined | null + age?: number | undefined | null +} +export function receiveAllOptionalObject(obj?: AllOptionalObject | undefined | null): 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 71c868a1..389ecefd 100644 --- a/examples/napi/src/object.rs +++ b/examples/napi/src/object.rs @@ -27,3 +27,18 @@ fn get_undefined(env: Env) -> Result { fn get_null(env: Env) -> Result { env.get_null() } + +#[napi(object)] +struct AllOptionalObject { + pub name: Option, + pub age: Option, +} + +#[napi] +fn receive_all_optional_object(obj: Option) -> Result<()> { + if !obj.is_none() { + assert!(obj.as_ref().unwrap().name.is_none()); + assert!(obj.as_ref().unwrap().age.is_none()); + } + Ok(()) +} From b2fea4d5b3aef4a4df4ccecca7cf7f5a30659e40 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Thu, 2 Dec 2021 16:25:20 +0800 Subject: [PATCH 3/4] fix(napi-derive): correct the aliased type generation --- crates/backend/src/typegen.rs | 20 ++++++++++++++++++-- crates/backend/src/typegen/const.rs | 3 ++- crates/backend/src/typegen/enum.rs | 3 ++- crates/backend/src/typegen/struct.rs | 3 ++- crates/macro/src/parser/attrs.rs | 7 +++---- examples/napi/__test__/typegen.spec.ts.md | 9 +++++++++ examples/napi/__test__/typegen.spec.ts.snap | Bin 1873 -> 1932 bytes examples/napi/__test__/values.spec.ts | 12 ++++++++++++ examples/napi/index.d.ts | 9 +++++++++ examples/napi/src/object.rs | 17 +++++++++++++++++ 10 files changed, 74 insertions(+), 9 deletions(-) diff --git a/crates/backend/src/typegen.rs b/crates/backend/src/typegen.rs index 2b86c926..e606fd09 100644 --- a/crates/backend/src/typegen.rs +++ b/crates/backend/src/typegen.rs @@ -3,7 +3,7 @@ mod r#enum; mod r#fn; pub(crate) mod r#struct; -use std::collections::HashMap; +use std::{cell::RefCell, collections::HashMap}; use once_cell::sync::Lazy; use syn::Type; @@ -17,6 +17,16 @@ pub struct TypeDef { pub js_doc: String, } +thread_local! { + static ALIAS: RefCell> = Default::default(); +} + +fn add_alias(name: String, alias: String) { + ALIAS.with(|aliases| { + aliases.borrow_mut().insert(name, alias); + }); +} + pub fn js_doc_from_comments(comments: &[String]) -> String { if comments.is_empty() { return "".to_owned(); @@ -248,7 +258,13 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool) -> (String, bool) { )); } else { // there should be runtime registered type in else - ts_ty = Some((rust_ty, false)); + let type_alias = ALIAS.with(|aliases| { + aliases + .borrow() + .get(rust_ty.as_str()) + .map(|a| (a.to_owned(), false)) + }); + ts_ty = type_alias.or_else(|| Some((rust_ty, false))); } } diff --git a/crates/backend/src/typegen/const.rs b/crates/backend/src/typegen/const.rs index 5ac266be..29343d3a 100644 --- a/crates/backend/src/typegen/const.rs +++ b/crates/backend/src/typegen/const.rs @@ -1,9 +1,10 @@ use super::{ToTypeDef, TypeDef}; -use crate::{js_doc_from_comments, ty_to_ts_type, NapiConst}; +use crate::{js_doc_from_comments, ty_to_ts_type, typegen::add_alias, NapiConst}; impl ToTypeDef for NapiConst { fn to_type_def(&self) -> TypeDef { + add_alias(self.name.to_string(), self.js_name.to_string()); TypeDef { kind: "const".to_owned(), name: self.js_name.to_owned(), diff --git a/crates/backend/src/typegen/enum.rs b/crates/backend/src/typegen/enum.rs index 3046c648..eeabbe53 100644 --- a/crates/backend/src/typegen/enum.rs +++ b/crates/backend/src/typegen/enum.rs @@ -1,8 +1,9 @@ -use super::{ToTypeDef, TypeDef}; +use super::{add_alias, ToTypeDef, TypeDef}; use crate::{js_doc_from_comments, NapiEnum}; impl ToTypeDef for NapiEnum { fn to_type_def(&self) -> TypeDef { + add_alias(self.name.to_string(), self.js_name.to_string()); TypeDef { kind: "enum".to_owned(), name: self.js_name.to_owned(), diff --git a/crates/backend/src/typegen/struct.rs b/crates/backend/src/typegen/struct.rs index d44a8b24..c592bf8b 100644 --- a/crates/backend/src/typegen/struct.rs +++ b/crates/backend/src/typegen/struct.rs @@ -1,7 +1,7 @@ use std::cell::RefCell; use std::collections::HashMap; -use super::{ToTypeDef, TypeDef}; +use super::{add_alias, ToTypeDef, TypeDef}; use crate::{js_doc_from_comments, ty_to_ts_type, NapiImpl, NapiStruct, NapiStructKind}; thread_local! { @@ -15,6 +15,7 @@ impl ToTypeDef for NapiStruct { c.borrow_mut() .insert(self.name.to_string(), self.js_name.clone()); }); + add_alias(self.name.to_string(), self.js_name.to_string()); TypeDef { kind: String::from(if self.kind == NapiStructKind::Object { "interface" diff --git a/crates/macro/src/parser/attrs.rs b/crates/macro/src/parser/attrs.rs index a04da0ef..111135d5 100644 --- a/crates/macro/src/parser/attrs.rs +++ b/crates/macro/src/parser/attrs.rs @@ -1,9 +1,8 @@ +use std::cell::{Cell, RefCell}; +use std::collections::HashMap; + use napi_derive_backend::{bail_span, BindgenResult, Diagnostic}; use proc_macro2::{Delimiter, Ident, Span, TokenTree}; -use std::{ - cell::{Cell, RefCell}, - collections::HashMap, -}; use syn::spanned::Spanned; thread_local! { diff --git a/examples/napi/__test__/typegen.spec.ts.md b/examples/napi/__test__/typegen.spec.ts.md index 546498dd..4b3b4e40 100644 --- a/examples/napi/__test__/typegen.spec.ts.md +++ b/examples/napi/__test__/typegen.spec.ts.md @@ -78,6 +78,15 @@ Generated by [AVA](https://avajs.dev). age?: number | undefined | null␊ }␊ export function receiveAllOptionalObject(obj?: AllOptionalObject | undefined | null): void␊ + export enum ALIAS {␊ + A = 0,␊ + B = 1␊ + }␊ + export interface AliasedStruct {␊ + a: ALIAS␊ + b: number␊ + }␊ + export function fnReceivedAliased(s: AliasedStruct, e: ALIAS): 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 8852cae6e3ea2a768385a88b906727190f2a3f7f..b73f0fe81fb13d3e92602bcefe849a7fbb51cd12 100644 GIT binary patch literal 1932 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 { @@ -208,6 +211,15 @@ test('option object', (t) => { t.notThrows(() => receiveAllOptionalObject({})) }) +test('aliased rust struct and enum', (t) => { + const a: ALIAS = ALIAS.A + const b: AliasedStruct = { + a, + b: 1, + } + t.notThrows(() => fnReceivedAliased(b, ALIAS.B)) +}) + test('serde-json', (t) => { const packageJson = readPackageJson() t.is(packageJson.name, 'napi-rs') diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index 216febe4..3e9dbb64 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -68,6 +68,15 @@ export interface AllOptionalObject { age?: number | undefined | null } export function receiveAllOptionalObject(obj?: AllOptionalObject | undefined | null): void +export enum ALIAS { + A = 0, + B = 1 +} +export interface AliasedStruct { + a: ALIAS + b: number +} +export function fnReceivedAliased(s: AliasedStruct, e: ALIAS): 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 389ecefd..6faeca0c 100644 --- a/examples/napi/src/object.rs +++ b/examples/napi/src/object.rs @@ -42,3 +42,20 @@ fn receive_all_optional_object(obj: Option) -> Result<()> { } Ok(()) } + +#[napi(js_name = "ALIAS")] +pub enum AliasedEnum { + A, + B, +} + +#[napi(object, js_name = "AliasedStruct")] +pub struct StructContainsAliasedEnum { + pub a: AliasedEnum, + pub b: u32, +} + +#[napi] +fn fn_received_aliased(mut s: StructContainsAliasedEnum, e: AliasedEnum) { + s.a = e; +} From 77e4241b18911ddfb0a9a67a39f33a6f6a9b5a59 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Thu, 2 Dec 2021 16:31:57 +0800 Subject: [PATCH 4/4] style: clippy fix --- crates/backend/src/codegen/struct.rs | 2 +- crates/backend/src/typegen.rs | 2 +- examples/napi/src/object.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/backend/src/codegen/struct.rs b/crates/backend/src/codegen/struct.rs index 07718f4a..655d6ab5 100644 --- a/crates/backend/src/codegen/struct.rs +++ b/crates/backend/src/codegen/struct.rs @@ -245,7 +245,7 @@ impl NapiStruct { }) = &ty { if let Some(last_path) = segments.last() { - last_path.ident.to_string() == "Option" + last_path.ident == "Option" } else { false } diff --git a/crates/backend/src/typegen.rs b/crates/backend/src/typegen.rs index e606fd09..8076e4b9 100644 --- a/crates/backend/src/typegen.rs +++ b/crates/backend/src/typegen.rs @@ -264,7 +264,7 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool) -> (String, bool) { .get(rust_ty.as_str()) .map(|a| (a.to_owned(), false)) }); - ts_ty = type_alias.or_else(|| Some((rust_ty, false))); + ts_ty = type_alias.or(Some((rust_ty, false))); } } diff --git a/examples/napi/src/object.rs b/examples/napi/src/object.rs index 6faeca0c..741c74cf 100644 --- a/examples/napi/src/object.rs +++ b/examples/napi/src/object.rs @@ -36,7 +36,7 @@ struct AllOptionalObject { #[napi] fn receive_all_optional_object(obj: Option) -> Result<()> { - if !obj.is_none() { + if obj.is_some() { assert!(obj.as_ref().unwrap().name.is_none()); assert!(obj.as_ref().unwrap().age.is_none()); }