From d56c9c56a8f145f4d4b2a76d1fd4e0d2d522a312 Mon Sep 17 00:00:00 2001 From: Gabriel Francisco Date: Fri, 22 Apr 2022 05:53:27 -0300 Subject: [PATCH] fix(napi-derive): simplify the optional values in generated declaration file (#1141) --- crates/backend/src/typegen.rs | 27 ++++++++++++++------ crates/backend/src/typegen/const.rs | 2 +- crates/backend/src/typegen/fn.rs | 8 +++--- crates/backend/src/typegen/struct.rs | 8 +++--- examples/napi/__test__/typegen.spec.ts.md | 16 ++++++------ examples/napi/__test__/typegen.spec.ts.snap | Bin 2932 -> 2919 bytes examples/napi/index.d.ts | 16 ++++++------ 7 files changed, 45 insertions(+), 32 deletions(-) diff --git a/crates/backend/src/typegen.rs b/crates/backend/src/typegen.rs index 75efceb7..916fbd37 100644 --- a/crates/backend/src/typegen.rs +++ b/crates/backend/src/typegen.rs @@ -213,9 +213,9 @@ fn fill_ty(template: &str, args: Vec) -> String { ret } -pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool) -> (String, bool) { +pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool, is_struct_field: bool) -> (String, bool) { match ty { - Type::Reference(r) => ty_to_ts_type(&r.elem, is_return_ty), + Type::Reference(r) => ty_to_ts_type(&r.elem, is_return_ty, is_struct_field), Type::Tuple(tuple) => { if tuple.elems.is_empty() { ("undefined".to_owned(), false) @@ -226,7 +226,7 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool) -> (String, bool) { tuple .elems .iter() - .map(|elem| ty_to_ts_type(elem, false).0) + .map(|elem| ty_to_ts_type(elem, false, false).0) .collect::>() .join(", ") ), @@ -244,7 +244,9 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool) -> (String, bool) { .args .iter() .filter_map(|arg| match arg { - syn::GenericArgument::Type(generic_ty) => Some(ty_to_ts_type(generic_ty, false)), + syn::GenericArgument::Type(generic_ty) => { + Some(ty_to_ts_type(generic_ty, false, false)) + } _ => None, }) .collect::>() @@ -255,9 +257,18 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool) -> (String, bool) { if rust_ty == "Result" && is_return_ty { ts_ty = Some(args.first().unwrap().to_owned()); } else if rust_ty == "Option" { - ts_ty = args - .first() - .map(|(arg, _)| (format!("{} | undefined | null", arg), true)); + ts_ty = args.first().map(|(arg, _)| { + ( + if is_struct_field { + arg.to_string() + } else if is_return_ty { + format!("{}?", arg) + } else { + format!("{} | undefined | null", arg) + }, + true, + ) + }); } else if rust_ty == "AsyncTask" { ts_ty = r#struct::TASK_STRUCTS.with(|t| { let (output_type, _) = args.first().unwrap().to_owned(); @@ -299,7 +310,7 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool) -> (String, bool) { ts_ty.unwrap_or_else(|| ("any".to_owned(), false)) } - Type::Group(g) => ty_to_ts_type(&g.elem, is_return_ty), + Type::Group(g) => ty_to_ts_type(&g.elem, is_return_ty, is_struct_field), _ => ("any".to_owned(), false), } } diff --git a/crates/backend/src/typegen/const.rs b/crates/backend/src/typegen/const.rs index 7def2c14..e926608d 100644 --- a/crates/backend/src/typegen/const.rs +++ b/crates/backend/src/typegen/const.rs @@ -17,7 +17,7 @@ impl ToTypeDef for NapiConst { def: format!( "export const {}: {}", &self.js_name, - ty_to_ts_type(&self.type_name, false).0 + ty_to_ts_type(&self.type_name, false, false).0 ), js_mod: self.js_mod.to_owned(), js_doc: js_doc_from_comments(&self.comments), diff --git a/crates/backend/src/typegen/fn.rs b/crates/backend/src/typegen/fn.rs index b1b2133d..91f65407 100644 --- a/crates/backend/src/typegen/fn.rs +++ b/crates/backend/src/typegen/fn.rs @@ -97,7 +97,7 @@ fn gen_callback_type(callback: &CallbackArg) -> String { .iter() .enumerate() .map(|(i, arg)| { - let (ts_type, is_optional) = ty_to_ts_type(arg, false); + let (ts_type, is_optional) = ty_to_ts_type(arg, false, false); FnArg { arg: format!("arg{}", i), ts_type, @@ -106,7 +106,7 @@ fn gen_callback_type(callback: &CallbackArg) -> String { }) .collect::(), ret = match &callback.ret { - Some(ty) => ty_to_ts_type(ty, true).0, + Some(ty) => ty_to_ts_type(ty, true, false).0, None => "void".to_owned(), } ) @@ -131,7 +131,7 @@ impl NapiFn { i.mutability = None; } let arg = path.pat.to_token_stream().to_string().to_case(Case::Camel); - let (ts_type, is_optional) = ty_to_ts_type(&path.ty, false); + let (ts_type, is_optional) = ty_to_ts_type(&path.ty, false, false); Some(FnArg { arg, @@ -181,7 +181,7 @@ impl NapiFn { .unwrap_or_else(|| "".to_owned()), _ => { let ret = if let Some(ret) = &self.ret { - let (ts_type, _) = ty_to_ts_type(ret, true); + let (ts_type, _) = ty_to_ts_type(ret, true, false); if ts_type == "undefined" { "void".to_owned() } else if ts_type == "Self" { diff --git a/crates/backend/src/typegen/struct.rs b/crates/backend/src/typegen/struct.rs index d09047bc..36968760 100644 --- a/crates/backend/src/typegen/struct.rs +++ b/crates/backend/src/typegen/struct.rs @@ -36,8 +36,10 @@ impl ToTypeDef for NapiImpl { fn to_type_def(&self) -> Option { if let Some(output_type) = &self.task_output_type { TASK_STRUCTS.with(|t| { - t.borrow_mut() - .insert(self.js_name.clone(), ty_to_ts_type(output_type, false).0); + t.borrow_mut().insert( + self.js_name.clone(), + ty_to_ts_type(output_type, false, true).0, + ); }); } @@ -90,7 +92,7 @@ impl NapiStruct { field_str.push_str("readonly ") } - let (arg, is_optional) = ty_to_ts_type(&f.ty, false); + let (arg, is_optional) = ty_to_ts_type(&f.ty, false, true); let arg = f.ts_type.as_ref().map(|ty| ty.to_string()).unwrap_or(arg); let sep = if is_optional { "?" } else { "" }; diff --git a/examples/napi/__test__/typegen.spec.ts.md b/examples/napi/__test__/typegen.spec.ts.md index 3a8c38e5..beea5282 100644 --- a/examples/napi/__test__/typegen.spec.ts.md +++ b/examples/napi/__test__/typegen.spec.ts.md @@ -46,7 +46,7 @@ Generated by [AVA](https://avajs.dev). export function chronoDateAdd1Minute(input: Date): Date␊ export interface Dates {␊ start: Date␊ - end?: Date | undefined | null␊ + end?: Date␊ }␊ export function eitherStringOrNumber(input: string | number): number␊ export function returnEither(input: number): string | number␊ @@ -106,7 +106,7 @@ Generated by [AVA](https://avajs.dev). export function xxh64Alias(input: Buffer): bigint␊ export function getMapping(): Record␊ export function sumMapping(nums: Record): number␊ - export function mapOption(val?: number | undefined | null): number | undefined | null␊ + export function mapOption(val?: number | undefined | null): number?␊ export function returnNull(): null␊ export function returnUndefined(): void␊ export function add(a: number, b: number): number␊ @@ -117,8 +117,8 @@ Generated by [AVA](https://avajs.dev). export function getUndefined(): void␊ export function getNull(): JsNull␊ export interface AllOptionalObject {␊ - name?: string | undefined | null␊ - age?: number | undefined | null␊ + name?: string␊ + age?: number␊ }␊ export function receiveAllOptionalObject(obj?: AllOptionalObject | undefined | null): void␊ export const enum ALIAS {␊ @@ -147,8 +147,8 @@ Generated by [AVA](https://avajs.dev). name: string␊ /** The version of the package */␊ version: string␊ - dependencies?: Record | undefined | null␊ - devDependencies?: Record | undefined | null␊ + dependencies?: Record␊ + devDependencies?: Record␊ }␊ export function readPackageJson(): PackageJson␊ export function getPackageJsonName(packageJson: PackageJson): string␊ @@ -221,7 +221,7 @@ Generated by [AVA](https://avajs.dev). export type Blake2bKey = Blake2BKey␊ export class Blake2BKey { }␊ export class Context {␊ - maybeNeed?: boolean | undefined | null␊ + maybeNeed?: boolean␊ constructor()␊ static withData(data: string): Context␊ method(): string␊ @@ -241,7 +241,7 @@ Generated by [AVA](https://avajs.dev). export type JsAssets = Assets␊ export class Assets {␊ constructor()␊ - get(id: number): JsAsset | undefined | null␊ + get(id: number): JsAsset?␊ }␊ export type JsAsset = Asset␊ export class Asset {␊ diff --git a/examples/napi/__test__/typegen.spec.ts.snap b/examples/napi/__test__/typegen.spec.ts.snap index 68e1450c4a8122191e5d68e64c1677b64a71bf62..0274c678eef07149edbcd10a2f0d7335694e72a1 100644 GIT binary patch literal 2919 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 R;TZgG<$v@o6%t%0001?hs`mf@ literal 2932 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 export function sumMapping(nums: Record): number -export function mapOption(val?: number | undefined | null): number | undefined | null +export function mapOption(val?: number | undefined | null): number? export function returnNull(): null export function returnUndefined(): void export function add(a: number, b: number): number @@ -107,8 +107,8 @@ export function getGlobal(): typeof global export function getUndefined(): void export function getNull(): JsNull export interface AllOptionalObject { - name?: string | undefined | null - age?: number | undefined | null + name?: string + age?: number } export function receiveAllOptionalObject(obj?: AllOptionalObject | undefined | null): void export const enum ALIAS { @@ -137,8 +137,8 @@ export interface PackageJson { name: string /** The version of the package */ version: string - dependencies?: Record | undefined | null - devDependencies?: Record | undefined | null + dependencies?: Record + devDependencies?: Record } export function readPackageJson(): PackageJson export function getPackageJsonName(packageJson: PackageJson): string @@ -211,7 +211,7 @@ export class Blake2BHasher { export type Blake2bKey = Blake2BKey export class Blake2BKey { } export class Context { - maybeNeed?: boolean | undefined | null + maybeNeed?: boolean constructor() static withData(data: string): Context method(): string @@ -231,7 +231,7 @@ export class NinjaTurtle { export type JsAssets = Assets export class Assets { constructor() - get(id: number): JsAsset | undefined | null + get(id: number): JsAsset? } export type JsAsset = Asset export class Asset {