From 47da28adb48502c797b835b2df4ba5874e8a8061 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Wed, 10 Nov 2021 19:04:36 +0800 Subject: [PATCH] feat(napi-derive): support const export --- crates/backend/src/ast.rs | 10 ++++- crates/backend/src/codegen.rs | 1 + crates/backend/src/codegen/const.rs | 41 ++++++++++++++++++++ crates/backend/src/lib.rs | 1 + crates/backend/src/typegen.rs | 1 + crates/backend/src/typegen/const.rs | 17 ++++++++ crates/macro/src/parser/mod.rs | 35 +++++++++++++++-- examples/napi/__test__/typegen.spec.ts.md | 3 +- examples/napi/__test__/typegen.spec.ts.snap | Bin 1097 -> 1115 bytes examples/napi/__test__/values.spec.ts | 5 +++ examples/napi/index.d.ts | 1 + examples/napi/src/lib.rs | 3 ++ 12 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 crates/backend/src/codegen/const.rs create mode 100644 crates/backend/src/typegen/const.rs diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index cb7421dd..3c17d872 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -1,5 +1,5 @@ use proc_macro2::Ident; -use syn::{Attribute, Type}; +use syn::{Attribute, Expr, Type}; #[derive(Debug, Clone)] pub struct NapiFn { @@ -93,3 +93,11 @@ pub struct NapiEnumVariant { pub val: i32, pub comments: Vec, } + +#[derive(Debug, Clone)] +pub struct NapiConst { + pub name: Ident, + pub js_name: String, + pub type_name: Type, + pub value: Expr, +} diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index 71657ee8..ccbddca8 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -2,6 +2,7 @@ use proc_macro2::{Ident, Span, TokenStream}; use crate::BindgenResult; +mod r#const; mod r#enum; mod r#fn; mod r#struct; diff --git a/crates/backend/src/codegen/const.rs b/crates/backend/src/codegen/const.rs new file mode 100644 index 00000000..ae4d04d4 --- /dev/null +++ b/crates/backend/src/codegen/const.rs @@ -0,0 +1,41 @@ +use proc_macro2::{Literal, TokenStream}; +use quote::ToTokens; + +use crate::{codegen::get_register_ident, BindgenResult, NapiConst, TryToTokens}; + +impl TryToTokens for NapiConst { + fn try_to_tokens(&self, tokens: &mut TokenStream) -> BindgenResult<()> { + let register = self.gen_module_register(); + (quote! { + #register + }) + .to_tokens(tokens); + + Ok(()) + } +} + +impl NapiConst { + fn gen_module_register(&self) -> TokenStream { + let name_str = self.name.to_string(); + let name_ident = self.name.clone(); + let js_name_lit = Literal::string(&self.js_name); + let register_name = get_register_ident(&name_str); + let type_name = &self.type_name; + quote! { + #[allow(non_snake_case)] + #[allow(clippy::all)] + #[napi::bindgen_prelude::ctor] + fn #register_name() { + use std::ffi::CString; + use std::ptr; + + unsafe fn cb(env: napi::sys::napi_env) -> napi::Result { + <#type_name as napi::bindgen_prelude::ToNapiValue>::to_napi_value(env, #name_ident) + } + + napi::bindgen_prelude::register_module_export(#js_name_lit, cb); + } + } + } +} diff --git a/crates/backend/src/lib.rs b/crates/backend/src/lib.rs index 918a8b4a..d9242d21 100644 --- a/crates/backend/src/lib.rs +++ b/crates/backend/src/lib.rs @@ -53,4 +53,5 @@ napi_ast_impl! { (Struct, NapiStruct), (Impl, NapiImpl), (Enum, NapiEnum), + (Const, NapiConst), } diff --git a/crates/backend/src/typegen.rs b/crates/backend/src/typegen.rs index a5197acb..12ff33da 100644 --- a/crates/backend/src/typegen.rs +++ b/crates/backend/src/typegen.rs @@ -1,3 +1,4 @@ +mod r#const; mod r#enum; mod r#fn; pub(crate) mod r#struct; diff --git a/crates/backend/src/typegen/const.rs b/crates/backend/src/typegen/const.rs new file mode 100644 index 00000000..94fc81c6 --- /dev/null +++ b/crates/backend/src/typegen/const.rs @@ -0,0 +1,17 @@ +use super::{ToTypeDef, TypeDef}; + +use crate::{ty_to_ts_type, NapiConst}; + +impl ToTypeDef for NapiConst { + fn to_type_def(&self) -> TypeDef { + TypeDef { + kind: "const".to_owned(), + name: self.js_name.to_owned(), + def: format!( + "export const {}: {}", + &self.js_name, + ty_to_ts_type(&self.type_name, false).0 + ), + } + } +} diff --git a/crates/macro/src/parser/mod.rs b/crates/macro/src/parser/mod.rs index 7d6aa765..4f864247 100644 --- a/crates/macro/src/parser/mod.rs +++ b/crates/macro/src/parser/mod.rs @@ -9,8 +9,9 @@ use attrs::{BindgenAttr, BindgenAttrs}; use convert_case::{Case, Casing}; use napi_derive_backend::{ - BindgenResult, CallbackArg, Diagnostic, FnKind, FnSelf, Napi, NapiEnum, NapiEnumVariant, NapiFn, - NapiFnArgKind, NapiImpl, NapiItem, NapiStruct, NapiStructField, NapiStructKind, + BindgenResult, CallbackArg, Diagnostic, FnKind, FnSelf, Napi, NapiConst, NapiEnum, + NapiEnumVariant, NapiFn, NapiFnArgKind, NapiImpl, NapiItem, NapiStruct, NapiStructField, + NapiStructKind, }; use proc_macro2::{Ident, TokenStream, TokenTree}; use quote::ToTokens; @@ -296,7 +297,7 @@ fn extract_doc_comments(attrs: &[syn::Attribute]) -> Vec { }) } -// Unescapes a quoted string. char::escape_debug() was used to escape the text. +// Unescaped a quoted string. char::escape_debug() was used to escape the text. fn try_unescape(s: &str) -> Option { if s.is_empty() { return Some(String::new()); @@ -584,6 +585,7 @@ impl ParseNapi for syn::Item { syn::Item::Struct(s) => s.parse_napi(tokens, opts), syn::Item::Impl(i) => i.parse_napi(tokens, opts), syn::Item::Enum(e) => e.parse_napi(tokens, opts), + syn::Item::Const(c) => c.parse_napi(tokens, opts), _ => bail_span!( self, "#[napi] can only be applied to a function, struct, enum or impl." @@ -625,6 +627,14 @@ impl ParseNapi for syn::ItemEnum { } } +impl ParseNapi for syn::ItemConst { + fn parse_napi(&mut self, tokens: &mut TokenStream, opts: BindgenAttrs) -> BindgenResult { + let napi = self.convert_to_ast(opts); + self.to_tokens(tokens); + napi + } +} + fn fn_kind(opts: &BindgenAttrs) -> FnKind { let mut kind = FnKind::Normal; @@ -910,3 +920,22 @@ impl ConvertToAST for syn::ItemEnum { }) } } + +impl ConvertToAST for syn::ItemConst { + fn convert_to_ast(&mut self, opts: BindgenAttrs) -> BindgenResult { + match self.vis { + Visibility::Public(_) => Ok(Napi { + comments: vec![], + item: NapiItem::Const(NapiConst { + name: self.ident.clone(), + js_name: opts + .js_name() + .map_or_else(|| self.ident.to_string(), |(s, _)| s.to_string()), + type_name: *self.ty.clone(), + value: *self.expr.clone(), + }), + }), + _ => bail_span!(self, "only public const allowed"), + } + } +} diff --git a/examples/napi/__test__/typegen.spec.ts.md b/examples/napi/__test__/typegen.spec.ts.md index 785d9c9d..937c2973 100644 --- a/examples/napi/__test__/typegen.spec.ts.md +++ b/examples/napi/__test__/typegen.spec.ts.md @@ -8,7 +8,8 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 - `export function getWords(): Array␊ + `export const DEFAULT_COST: number␊ + export function getWords(): Array␊ export function getNums(): Array␊ export function sumNums(nums: Array): number␊ export function readFileAsync(path: string): Promise␊ diff --git a/examples/napi/__test__/typegen.spec.ts.snap b/examples/napi/__test__/typegen.spec.ts.snap index fae58d3b0e3806c4b2fb13fb1c464d11abf9e4a3..f58e243cfbf800004144eee0f5368207b262b8a3 100644 GIT binary patch literal 1115 zcmV-h1f=^xRzV zR?Uv%L=eufLP)EzyAE`XaD^5 z`)|J-)y!}3tX6wc`^d^iAJ#tp;LB%lKNnJyKyal=r`v1Yz8U?{9t=kw;YsX+e7Z!8 z6CP+LIGKQcD`cpgx<^`4()78~lJUt!8M2?mIbgk|2 z+9m!C8l>cmXl5j?Pfr~1wvAWco}Nmvu({<_ zWl2ougSnBMI~rYjn~)Xq?LB+NYR_slQ?RwVFVV)#7n}wGbNGI6#FWO1d=05`g#XSX z_<%s~?T=ZdqoxT*rc+kqFC*d8$Y69j2QelSyHEzbT}7fYz_uqxmhF}5mj=tU#+xWn z%|^qS7usP-gWQzK4R#SafmaH7Ou29x!>RyG^?+1pBDWI49MESTFi?2i-#~z)Wf?GR zIy}87yI-Ss*ZE(n#Y{GBFz2_4OzyQTfVu5H9uQ~G`h81x-IIzpFSw?RD@S1^2I~;H zL}Q-?of~A!R#Ct=>Q8{$AIRxM8ar69e_#3JjZythIpoeMfi|Cr0WL8#2wEeG6 z?JWH>O%wGDUw|#Jn~FrYd|Yi~+@y#i?EV$?yl;3LwnL~~qS%B}JcdON?aKlDW|o>x zOG8D+&|5C&N9^(OFPKb|ONiJ;|3xIVJ=3=w! hjd{LBnjSUeX<38L8S59~?-eM}#J|mz$R%$K005wMA;16t literal 1097 zcmV-P1h)G@RzV;%NTPOCO5}00000000A> zR?TiBMG$saA*9t_IB`RL97{uFCn3OSH<9xP*###eS*;M_&@)pW_qwOs>h6g%3V97) z0Um-ILgLPuSK!E*>K>0h_ROpeKG@aWUwu_wT|XwBPG_g{DbRF&pMqaoe!M6^M2>U_db3G_fx418D%0eObU{Kc_US37TO40neHj0Vl z=xGCTn57k<$kGs09jLR^0r6a~VNth`YDx-de8D&jbS@%qO3gSRg(s+Utz^nHJU_`s zqb7^gDt(i2!)|BNqbe!QRCL?C4Ozm38N{(i19HNWOJRHxmSVRQYI+fRY@j&wwu4V4dJxDXGYhBoi@=n1I+Pc+fvC zsjEjQi;VM))_|EYs2it$rG_rH9uw2dR9F{p(E8>kQ{voFmC6g9HI^0+_FIgi5K75` zilupcW>6y<0l5m_l82{++||uIwir6tXb2_bt=$%INnSA#lLvAp6Y_%ed~!++3VolP zWzhtsJ@UAMKh3m}wu;W}>VaGdDDary7LLMLf!*8p$%V`mN(VlS1HBY-_ycneO*`-n7;Z8ye)YOs=tu&;(v; zsn#>uw!wyJ++JUFEnk`3w#YW!)_`wGYE0_ z6yv5O=h*#Q>Uq=fwrtx_`9!lsP`rji-?+sV{C1YwPD^7=M{qIUu8!E<-CcZS3@fJS z_dmF~iBem=ni|*bvWrIHf9AvND*h9>{}oOuF%hR)lYw9<<*s_IWhr=0COC`&Hz*1fUcZ; { + t.is(DEFAULT_COST, 12) +}) + test('number', (t) => { t.is(add(1, 2), 3) t.is(fibonacci(5), 5) diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index 4a78e624..396941f4 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -1,3 +1,4 @@ +export const DEFAULT_COST: number export function getWords(): Array export function getNums(): Array export function sumNums(nums: Array): number diff --git a/examples/napi/src/lib.rs b/examples/napi/src/lib.rs index bbd3e620..a06b7695 100644 --- a/examples/napi/src/lib.rs +++ b/examples/napi/src/lib.rs @@ -3,6 +3,9 @@ extern crate napi_derive; #[macro_use] extern crate serde_derive; +#[napi] +pub const DEFAULT_COST: u32 = 12; + mod array; mod r#async; mod bigint;