From 6f40f94d09d4a0f1adb876082bc34c4fc04ac974 Mon Sep 17 00:00:00 2001 From: liuyi Date: Wed, 13 Dec 2023 15:23:00 +0800 Subject: [PATCH] fix(napi-derive): more accurate napi expanding error (#1854) --- crates/macro/src/parser/mod.rs | 77 +++++++++++++------ .../build_error_tests/ts_arg_type_2.stderr | 2 +- .../build_error_tests/ts_arg_type_3.stderr | 6 +- .../build_error_tests/ts_arg_type_4.stderr | 6 +- 4 files changed, 62 insertions(+), 29 deletions(-) diff --git a/crates/macro/src/parser/mod.rs b/crates/macro/src/parser/mod.rs index 7165ee0c..bfde66b4 100644 --- a/crates/macro/src/parser/mod.rs +++ b/crates/macro/src/parser/mod.rs @@ -18,7 +18,8 @@ use proc_macro2::{Ident, Span, TokenStream}; use quote::ToTokens; use syn::ext::IdentExt; use syn::parse::{Parse, ParseStream, Result as SynResult}; -use syn::{Attribute, ExprLit, PatType, PathSegment, Signature, Type, Visibility}; +use syn::spanned::Spanned; +use syn::{Attribute, ExprLit, Meta, PatType, PathSegment, Signature, Type, Visibility}; use crate::parser::attrs::{check_recorded_struct_for_impl, record_struct}; @@ -81,29 +82,61 @@ fn find_ts_arg_type_and_remove_attribute( ts_args_type ); } - let inner: syn::Expr = attr.parse_args()?; - match inner { - syn::Expr::Assign(syn::ExprAssign { left, right, .. }) => { - let left = match *left { - syn::Expr::Path(syn::ExprPath { path, .. }) => path, - _ => bail_span!(left, "Expected path"), - }; - if !left.is_ident("ts_arg_type") { - bail_span!(left, "Expected 'ts_arg_type'"); - } - - let right = match *right { - syn::Expr::Lit(syn::ExprLit { - lit: syn::Lit::Str(lit), - .. - }) => lit, - _ => bail_span!(right, "Expected string literal"), - }; - ts_type_attr = Some((idx, right.value())); + match &attr.meta { + syn::Meta::Path(_) | syn::Meta::NameValue(_) => { + bail_span!( + attr, + "Expects an assignment #[napi(ts_arg_type = \"MyType\")]" + ) } - _ => bail_span!(inner, "Expected assignment [ts_arg_type = \"MyType\"]"), - }; + syn::Meta::List(list) => { + let mut found = false; + list + .parse_args_with(|tokens: &syn::parse::ParseBuffer<'_>| { + // tokens: + // #[napi(xxx, xxx=xxx)] + // ^^^^^^^^^^^^ + let list = tokens.parse_terminated(Meta::parse, Token![,])?; + + for meta in list { + if meta.path().is_ident("ts_arg_type") { + match meta { + Meta::Path(_) | Meta::List(_) => { + return Err(syn::Error::new( + meta.path().span(), + "Expects an assignment (ts_arg_type = \"MyType\")", + )) + } + Meta::NameValue(name_value) => match name_value.value { + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(str), + .. + }) => { + let value = str.value(); + found = true; + ts_type_attr = Some((idx, value)); + } + _ => { + return Err(syn::Error::new( + name_value.value.span(), + "Expects a string literal", + )) + } + }, + } + } + } + + Ok(()) + }) + .map_err(Diagnostic::from)?; + + if !found { + bail_span!(attr, "Expects a 'ts_arg_type'"); + } + } + } } } diff --git a/examples/napi/tests/build_error_tests/ts_arg_type_2.stderr b/examples/napi/tests/build_error_tests/ts_arg_type_2.stderr index 644d5475..e23c321d 100644 --- a/examples/napi/tests/build_error_tests/ts_arg_type_2.stderr +++ b/examples/napi/tests/build_error_tests/ts_arg_type_2.stderr @@ -1,4 +1,4 @@ -error: Expected string literal +error: Expects a string literal --> tests/build_error_tests/ts_arg_type_2.rs:7:41 | 7 | pub fn add(u: u32, #[napi(ts_arg_type = 32)] f: Option) { diff --git a/examples/napi/tests/build_error_tests/ts_arg_type_3.stderr b/examples/napi/tests/build_error_tests/ts_arg_type_3.stderr index deb6cb88..427001be 100644 --- a/examples/napi/tests/build_error_tests/ts_arg_type_3.stderr +++ b/examples/napi/tests/build_error_tests/ts_arg_type_3.stderr @@ -1,5 +1,5 @@ -error: unexpected token - --> tests/build_error_tests/ts_arg_type_3.rs:7:38 +error: Expects an assignment (ts_arg_type = "MyType") + --> tests/build_error_tests/ts_arg_type_3.rs:7:27 | 7 | pub fn add(u: u32, #[napi(ts_arg_type, not_expected)] f: Option) { - | ^ + | ^^^^^^^^^^^ diff --git a/examples/napi/tests/build_error_tests/ts_arg_type_4.stderr b/examples/napi/tests/build_error_tests/ts_arg_type_4.stderr index e57ac42e..3e5ab129 100644 --- a/examples/napi/tests/build_error_tests/ts_arg_type_4.stderr +++ b/examples/napi/tests/build_error_tests/ts_arg_type_4.stderr @@ -1,5 +1,5 @@ -error: Expected 'ts_arg_type' - --> tests/build_error_tests/ts_arg_type_4.rs:7:27 +error: Expects a 'ts_arg_type' + --> tests/build_error_tests/ts_arg_type_4.rs:7:20 | 7 | pub fn add(u: u32, #[napi(not_expected = "obj")] f: Option) { - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^