fix(napi-derive): upgrade syn (#1849)
This commit is contained in:
parent
e3902e001f
commit
e32c105a26
12 changed files with 284 additions and 261 deletions
|
@ -21,7 +21,7 @@ type-def = ["regex", "once_cell", "semver"]
|
|||
convert_case = "0.6"
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
syn = { version = "1.0.61", features = ["fold", "full", "extra-traits"] }
|
||||
syn = { version = "2", features = ["fold", "full", "extra-traits"] }
|
||||
|
||||
[dependencies.regex]
|
||||
optional = true
|
||||
|
|
|
@ -24,9 +24,9 @@ type-def = ["napi-derive-backend/type-def"]
|
|||
[dependencies]
|
||||
convert_case = "0.6"
|
||||
napi-derive-backend = { version = "1.0.56", path = "../backend" }
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
syn = { version = "1.0.61", features = ["fold", "full", "extra-traits"] }
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
syn = { version = "2", features = ["fold", "full", "extra-traits"] }
|
||||
cfg-if = "1.0"
|
||||
|
||||
[lib]
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::parser::{attrs::BindgenAttrs, ParseNapi};
|
|||
#[cfg(feature = "type-def")]
|
||||
use napi_derive_backend::ToTypeDef;
|
||||
use napi_derive_backend::{BindgenResult, Napi, TryToTokens};
|
||||
use proc_macro2::{TokenStream, TokenTree};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
use syn::{Attribute, Item};
|
||||
|
||||
|
@ -66,7 +66,7 @@ pub fn expand(attr: TokenStream, input: TokenStream) -> BindgenResult<TokenStrea
|
|||
.attrs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, m)| m.path.segments[0].ident == "napi");
|
||||
.find(|(_, m)| m.path().is_ident("napi"));
|
||||
if mod_in_mod.is_some() {
|
||||
bail_span!(
|
||||
mod_,
|
||||
|
@ -79,7 +79,8 @@ pub fn expand(attr: TokenStream, input: TokenStream) -> BindgenResult<TokenStrea
|
|||
_ => &mut empty_attrs,
|
||||
},
|
||||
) {
|
||||
let napi = item.parse_napi(&mut tokens, item_opts)?;
|
||||
let napi = item.parse_napi(&mut tokens, &item_opts)?;
|
||||
item_opts.check_used()?;
|
||||
napi.try_to_tokens(&mut tokens)?;
|
||||
|
||||
#[cfg(feature = "type-def")]
|
||||
|
@ -96,14 +97,15 @@ pub fn expand(attr: TokenStream, input: TokenStream) -> BindgenResult<TokenStrea
|
|||
.attrs
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter(|attr| attr.path.segments[0].ident != "napi")
|
||||
.filter(|attr| attr.path().is_ident("napi"))
|
||||
.collect();
|
||||
let mod_name = js_mod.ident;
|
||||
let visible = js_mod.vis;
|
||||
let mod_tokens = quote! { #(#js_mod_attrs)* #visible mod #mod_name { #tokens } };
|
||||
Ok(mod_tokens)
|
||||
} else {
|
||||
let napi = item.parse_napi(&mut tokens, opts)?;
|
||||
let napi = item.parse_napi(&mut tokens, &opts)?;
|
||||
opts.check_used()?;
|
||||
napi.try_to_tokens(&mut tokens)?;
|
||||
|
||||
#[cfg(feature = "type-def")]
|
||||
|
@ -155,41 +157,28 @@ fn replace_napi_attr_in_mod(
|
|||
js_namespace: String,
|
||||
attrs: &mut Vec<syn::Attribute>,
|
||||
) -> Option<BindgenAttrs> {
|
||||
let napi_attr = attrs.clone();
|
||||
let napi_attr = napi_attr
|
||||
let napi_attr = attrs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, m)| m.path.segments[0].ident == "napi");
|
||||
if let Some((index, napi_attr)) = napi_attr {
|
||||
let attr_token_stream = napi_attr.tokens.clone();
|
||||
let raw_attr_stream = attr_token_stream.to_string();
|
||||
let raw_attr_stream = if !raw_attr_stream.is_empty() {
|
||||
raw_attr_stream
|
||||
.strip_prefix('(')
|
||||
.unwrap()
|
||||
.strip_suffix(')')
|
||||
.unwrap()
|
||||
.to_string()
|
||||
} else {
|
||||
raw_attr_stream
|
||||
};
|
||||
let raw_attr_token_stream = syn::parse_str::<TokenStream>(raw_attr_stream.as_str()).unwrap();
|
||||
.find(|(_, m)| m.path().is_ident("napi"));
|
||||
|
||||
let new_attr: syn::Attribute = if !raw_attr_stream.is_empty() {
|
||||
syn::parse_quote!(
|
||||
#[napi(#raw_attr_token_stream, namespace = #js_namespace)]
|
||||
)
|
||||
} else {
|
||||
syn::parse_quote!(
|
||||
#[napi(namespace = #js_namespace)]
|
||||
)
|
||||
};
|
||||
let struct_opts: BindgenAttrs =
|
||||
if let Some(TokenTree::Group(g)) = new_attr.tokens.into_iter().next() {
|
||||
syn::parse2(g.stream()).ok()?
|
||||
} else {
|
||||
syn::parse2(quote! {}).ok()?
|
||||
if let Some((index, napi_attr)) = napi_attr {
|
||||
// adds `namespace = #js_namespace` into `#[napi]` attribute
|
||||
let new_attr = match &napi_attr.meta {
|
||||
syn::Meta::Path(_) => {
|
||||
syn::parse_quote!(#[napi(namespace = #js_namespace)])
|
||||
}
|
||||
syn::Meta::List(list) => {
|
||||
let existing = list.tokens.clone();
|
||||
syn::parse_quote!(#[napi(#existing, namespace = #js_namespace)])
|
||||
}
|
||||
syn::Meta::NameValue(name_value) => {
|
||||
let existing = &name_value.value;
|
||||
syn::parse_quote!(#[napi(#existing, namespace = #js_namespace)])
|
||||
}
|
||||
};
|
||||
|
||||
let struct_opts = BindgenAttrs::try_from(&new_attr).unwrap();
|
||||
attrs.remove(index);
|
||||
Some(struct_opts)
|
||||
} else {
|
||||
|
|
|
@ -24,7 +24,7 @@ fn find_and_remove_napi_attr(attrs: &mut Vec<Attribute>) {
|
|||
let napi_attr = attrs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|&(_, m)| m.path.segments[0].ident == "napi");
|
||||
.find(|&(_, m)| m.path().segments[0].ident == "napi");
|
||||
|
||||
let pos = match napi_attr {
|
||||
Some((pos, _raw_attr)) => pos,
|
||||
|
|
|
@ -3,7 +3,12 @@ use std::collections::HashMap;
|
|||
|
||||
use napi_derive_backend::{bail_span, BindgenResult, Diagnostic};
|
||||
use proc_macro2::{Delimiter, Ident, Span, TokenTree};
|
||||
use quote::ToTokens;
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
use syn::spanned::Spanned;
|
||||
use syn::Attribute;
|
||||
|
||||
use crate::parser::AnyIdent;
|
||||
|
||||
thread_local! {
|
||||
static ATTRS: AttributeParseState = Default::default();
|
||||
|
@ -23,6 +28,7 @@ struct ParsedStruct {
|
|||
#[derive(Default)]
|
||||
struct AttributeParseState {
|
||||
parsed: Cell<usize>,
|
||||
#[allow(unused)]
|
||||
checks: Cell<usize>,
|
||||
}
|
||||
|
||||
|
@ -84,7 +90,8 @@ macro_rules! methods {
|
|||
$(methods!(@method $name, $variant($($contents)*));)*
|
||||
|
||||
#[cfg(feature = "strict")]
|
||||
fn check_used(self) -> Result<(), Diagnostic> {
|
||||
#[allow(unused)]
|
||||
pub fn check_used(&self) -> Result<(), Diagnostic> {
|
||||
// Account for the fact this method was called
|
||||
ATTRS.with(|state| state.checks.set(state.checks.get() + 1));
|
||||
|
||||
|
@ -102,7 +109,7 @@ macro_rules! methods {
|
|||
}
|
||||
|
||||
#[cfg(not(feature = "strict"))]
|
||||
fn check_used(self) -> Result<(), Diagnostic> {
|
||||
pub fn check_used(&self) -> Result<(), Diagnostic> {
|
||||
// Account for the fact this method was called
|
||||
ATTRS.with(|state| state.checks.set(state.checks.get() + 1));
|
||||
Ok(())
|
||||
|
@ -191,43 +198,58 @@ macro_rules! methods {
|
|||
impl BindgenAttrs {
|
||||
/// Find and parse the napi attributes.
|
||||
pub fn find(attrs: &mut Vec<syn::Attribute>) -> Result<BindgenAttrs, Diagnostic> {
|
||||
let mut ret = BindgenAttrs::default();
|
||||
loop {
|
||||
let napi_attr = attrs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|&(_, m)| m.path.segments[0].ident == "napi");
|
||||
for (index, attr) in attrs.iter().enumerate() {
|
||||
let attr = BindgenAttrs::try_from(attr)?;
|
||||
if attr.exists {
|
||||
attrs.remove(index);
|
||||
|
||||
let pos = match napi_attr {
|
||||
Some((pos, raw_attr)) => {
|
||||
ret.exists = true;
|
||||
ret.span = raw_attr.tokens.span();
|
||||
pos
|
||||
return Ok(attr);
|
||||
}
|
||||
None => return Ok(ret),
|
||||
};
|
||||
let attr = attrs.remove(pos);
|
||||
let mut tts = attr.tokens.clone().into_iter();
|
||||
let group = match tts.next() {
|
||||
Some(TokenTree::Group(d)) => d,
|
||||
Some(_) => bail_span!(attr, "malformed #[napi] attribute"),
|
||||
None => continue,
|
||||
};
|
||||
if tts.next().is_some() {
|
||||
bail_span!(attr, "malformed #[napi] attribute");
|
||||
}
|
||||
if group.delimiter() != Delimiter::Parenthesis {
|
||||
bail_span!(attr, "malformed #[napi] attribute");
|
||||
}
|
||||
let mut attrs: BindgenAttrs = syn::parse2(group.stream())?;
|
||||
ret.attrs.append(&mut attrs.attrs);
|
||||
attrs.check_used()?;
|
||||
}
|
||||
|
||||
Ok(BindgenAttrs::default())
|
||||
}
|
||||
|
||||
attrgen!(methods);
|
||||
}
|
||||
|
||||
impl TryFrom<&Attribute> for BindgenAttrs {
|
||||
type Error = Diagnostic;
|
||||
|
||||
fn try_from(attr: &Attribute) -> Result<Self, Self::Error> {
|
||||
let mut ret = BindgenAttrs {
|
||||
exists: false,
|
||||
attrs: vec![],
|
||||
span: Span::call_site(),
|
||||
};
|
||||
|
||||
if attr.path().is_ident("napi") {
|
||||
ret.exists = true;
|
||||
ret.span = attr.span();
|
||||
|
||||
let tts = attr.meta.to_token_stream().into_iter();
|
||||
let group = match tts.last() {
|
||||
// #[napi(xxx)]
|
||||
// ^^^^^^^^^
|
||||
Some(TokenTree::Group(d)) => d,
|
||||
// #[napi]
|
||||
// ^^^^
|
||||
Some(TokenTree::Ident(_)) => parse_quote!(()),
|
||||
_ => bail_span!(attr, "invalid #[napi] attribute"),
|
||||
};
|
||||
|
||||
if group.delimiter() != Delimiter::Parenthesis {
|
||||
bail_span!(attr, "malformed #[napi] attribute");
|
||||
}
|
||||
|
||||
let mut attrs: BindgenAttrs = syn::parse2(group.stream())?;
|
||||
ret.attrs.append(&mut attrs.attrs);
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for BindgenAttrs {
|
||||
fn default() -> BindgenAttrs {
|
||||
// Add 1 to the list of parsed attribute sets. We'll use this counter to
|
||||
|
@ -297,3 +319,129 @@ pub fn check_recorded_struct_for_impl(ident: &Ident, opts: &BindgenAttrs) -> Bin
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
impl Parse for BindgenAttrs {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let mut attrs = BindgenAttrs::default();
|
||||
if input.is_empty() {
|
||||
return Ok(attrs);
|
||||
}
|
||||
|
||||
let opts = syn::punctuated::Punctuated::<_, syn::token::Comma>::parse_terminated(input)?;
|
||||
attrs.attrs = opts.into_iter().map(|c| (Cell::new(false), c)).collect();
|
||||
Ok(attrs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for BindgenAttr {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let original = input.fork();
|
||||
let attr: AnyIdent = input.parse()?;
|
||||
let attr = attr.0;
|
||||
let attr_span = attr.span();
|
||||
let attr_string = attr.to_string();
|
||||
let raw_attr_string = format!("r#{}", attr_string);
|
||||
|
||||
macro_rules! parsers {
|
||||
($(($name:ident, $($contents:tt)*),)*) => {
|
||||
$(
|
||||
if attr_string == stringify!($name) || raw_attr_string == stringify!($name) {
|
||||
parsers!(
|
||||
@parser
|
||||
$($contents)*
|
||||
);
|
||||
}
|
||||
)*
|
||||
};
|
||||
|
||||
(@parser $variant:ident(Span)) => ({
|
||||
return Ok(BindgenAttr::$variant(attr_span));
|
||||
});
|
||||
|
||||
(@parser $variant:ident(Span, Ident)) => ({
|
||||
input.parse::<Token![=]>()?;
|
||||
let ident = input.parse::<AnyIdent>()?.0;
|
||||
return Ok(BindgenAttr::$variant(attr_span, ident))
|
||||
});
|
||||
|
||||
(@parser $variant:ident(Span, Option<Ident>)) => ({
|
||||
if input.parse::<Token![=]>().is_ok() {
|
||||
let ident = input.parse::<AnyIdent>()?.0;
|
||||
return Ok(BindgenAttr::$variant(attr_span, Some(ident)))
|
||||
} else {
|
||||
return Ok(BindgenAttr::$variant(attr_span, None));
|
||||
}
|
||||
});
|
||||
|
||||
(@parser $variant:ident(Span, syn::Path)) => ({
|
||||
input.parse::<Token![=]>()?;
|
||||
return Ok(BindgenAttr::$variant(attr_span, input.parse()?));
|
||||
});
|
||||
|
||||
(@parser $variant:ident(Span, syn::Expr)) => ({
|
||||
input.parse::<Token![=]>()?;
|
||||
return Ok(BindgenAttr::$variant(attr_span, input.parse()?));
|
||||
});
|
||||
|
||||
(@parser $variant:ident(Span, String, Span)) => ({
|
||||
input.parse::<Token![=]>()?;
|
||||
let (val, span) = match input.parse::<syn::LitStr>() {
|
||||
Ok(str) => (str.value(), str.span()),
|
||||
Err(_) => {
|
||||
let ident = input.parse::<AnyIdent>()?.0;
|
||||
(ident.to_string(), ident.span())
|
||||
}
|
||||
};
|
||||
return Ok(BindgenAttr::$variant(attr_span, val, span))
|
||||
});
|
||||
|
||||
(@parser $variant:ident(Span, Option<bool>)) => ({
|
||||
if let Ok(_) = input.parse::<Token![=]>() {
|
||||
let (val, _) = match input.parse::<syn::LitBool>() {
|
||||
Ok(str) => (str.value(), str.span()),
|
||||
Err(_) => {
|
||||
let ident = input.parse::<AnyIdent>()?.0;
|
||||
(true, ident.span())
|
||||
}
|
||||
};
|
||||
return Ok::<BindgenAttr, syn::Error>(BindgenAttr::$variant(attr_span, Some(val)))
|
||||
} else {
|
||||
return Ok(BindgenAttr::$variant(attr_span, Some(true)))
|
||||
}
|
||||
});
|
||||
|
||||
(@parser $variant:ident(Span, Vec<String>, Vec<Span>)) => ({
|
||||
input.parse::<Token![=]>()?;
|
||||
let (vals, spans) = match input.parse::<syn::ExprArray>() {
|
||||
Ok(exprs) => {
|
||||
let mut vals = vec![];
|
||||
let mut spans = vec![];
|
||||
|
||||
for expr in exprs.elems.iter() {
|
||||
if let syn::Expr::Lit(syn::ExprLit {
|
||||
lit: syn::Lit::Str(ref str),
|
||||
..
|
||||
}) = expr {
|
||||
vals.push(str.value());
|
||||
spans.push(str.span());
|
||||
} else {
|
||||
return Err(syn::Error::new(expr.span(), "expected string literals"));
|
||||
}
|
||||
}
|
||||
|
||||
(vals, spans)
|
||||
},
|
||||
Err(_) => {
|
||||
let ident = input.parse::<AnyIdent>()?.0;
|
||||
(vec![ident.to_string()], vec![ident.span()])
|
||||
}
|
||||
};
|
||||
return Ok(BindgenAttr::$variant(attr_span, vals, spans))
|
||||
});
|
||||
}
|
||||
|
||||
attrgen!(parsers);
|
||||
|
||||
Err(original.error("unknown attribute"))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
#[macro_use]
|
||||
pub mod attrs;
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::str::Chars;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
|
||||
use attrs::{BindgenAttr, BindgenAttrs};
|
||||
use attrs::BindgenAttrs;
|
||||
|
||||
use convert_case::{Case, Casing};
|
||||
use napi_derive_backend::{
|
||||
|
@ -14,11 +14,11 @@ use napi_derive_backend::{
|
|||
NapiEnumVariant, NapiFn, NapiFnArg, NapiFnArgKind, NapiImpl, NapiItem, NapiStruct,
|
||||
NapiStructField, NapiStructKind,
|
||||
};
|
||||
use proc_macro2::{Ident, Span, TokenStream, TokenTree};
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::ToTokens;
|
||||
use syn::ext::IdentExt;
|
||||
use syn::parse::{Parse, ParseStream, Result as SynResult};
|
||||
use syn::{Attribute, Meta, NestedMeta, PatType, PathSegment, Signature, Type, Visibility};
|
||||
use syn::{Attribute, ExprLit, PatType, PathSegment, Signature, Type, Visibility};
|
||||
|
||||
use crate::parser::attrs::{check_recorded_struct_for_impl, record_struct};
|
||||
|
||||
|
@ -48,138 +48,12 @@ impl Parse for AnyIdent {
|
|||
}
|
||||
}
|
||||
|
||||
impl Parse for BindgenAttrs {
|
||||
fn parse(input: ParseStream) -> SynResult<Self> {
|
||||
let mut attrs = BindgenAttrs::default();
|
||||
if input.is_empty() {
|
||||
return Ok(attrs);
|
||||
}
|
||||
|
||||
let opts = syn::punctuated::Punctuated::<_, syn::token::Comma>::parse_terminated(input)?;
|
||||
attrs.attrs = opts.into_iter().map(|c| (Cell::new(false), c)).collect();
|
||||
Ok(attrs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for BindgenAttr {
|
||||
fn parse(input: ParseStream) -> SynResult<Self> {
|
||||
let original = input.fork();
|
||||
let attr: AnyIdent = input.parse()?;
|
||||
let attr = attr.0;
|
||||
let attr_span = attr.span();
|
||||
let attr_string = attr.to_string();
|
||||
let raw_attr_string = format!("r#{}", attr_string);
|
||||
|
||||
macro_rules! parsers {
|
||||
($(($name:ident, $($contents:tt)*),)*) => {
|
||||
$(
|
||||
if attr_string == stringify!($name) || raw_attr_string == stringify!($name) {
|
||||
parsers!(
|
||||
@parser
|
||||
$($contents)*
|
||||
);
|
||||
}
|
||||
)*
|
||||
};
|
||||
|
||||
(@parser $variant:ident(Span)) => ({
|
||||
return Ok(BindgenAttr::$variant(attr_span));
|
||||
});
|
||||
|
||||
(@parser $variant:ident(Span, Ident)) => ({
|
||||
input.parse::<Token![=]>()?;
|
||||
let ident = input.parse::<AnyIdent>()?.0;
|
||||
return Ok(BindgenAttr::$variant(attr_span, ident))
|
||||
});
|
||||
|
||||
(@parser $variant:ident(Span, Option<Ident>)) => ({
|
||||
if input.parse::<Token![=]>().is_ok() {
|
||||
let ident = input.parse::<AnyIdent>()?.0;
|
||||
return Ok(BindgenAttr::$variant(attr_span, Some(ident)))
|
||||
} else {
|
||||
return Ok(BindgenAttr::$variant(attr_span, None));
|
||||
}
|
||||
});
|
||||
|
||||
(@parser $variant:ident(Span, syn::Path)) => ({
|
||||
input.parse::<Token![=]>()?;
|
||||
return Ok(BindgenAttr::$variant(attr_span, input.parse()?));
|
||||
});
|
||||
|
||||
(@parser $variant:ident(Span, syn::Expr)) => ({
|
||||
input.parse::<Token![=]>()?;
|
||||
return Ok(BindgenAttr::$variant(attr_span, input.parse()?));
|
||||
});
|
||||
|
||||
(@parser $variant:ident(Span, String, Span)) => ({
|
||||
input.parse::<Token![=]>()?;
|
||||
let (val, span) = match input.parse::<syn::LitStr>() {
|
||||
Ok(str) => (str.value(), str.span()),
|
||||
Err(_) => {
|
||||
let ident = input.parse::<AnyIdent>()?.0;
|
||||
(ident.to_string(), ident.span())
|
||||
}
|
||||
};
|
||||
return Ok(BindgenAttr::$variant(attr_span, val, span))
|
||||
});
|
||||
|
||||
(@parser $variant:ident(Span, Option<bool>)) => ({
|
||||
if let Ok(_) = input.parse::<Token![=]>() {
|
||||
let (val, _) = match input.parse::<syn::LitBool>() {
|
||||
Ok(str) => (str.value(), str.span()),
|
||||
Err(_) => {
|
||||
let ident = input.parse::<AnyIdent>()?.0;
|
||||
(true, ident.span())
|
||||
}
|
||||
};
|
||||
return Ok::<BindgenAttr, syn::Error>(BindgenAttr::$variant(attr_span, Some(val)))
|
||||
} else {
|
||||
return Ok(BindgenAttr::$variant(attr_span, Some(true)))
|
||||
}
|
||||
});
|
||||
|
||||
(@parser $variant:ident(Span, Vec<String>, Vec<Span>)) => ({
|
||||
input.parse::<Token![=]>()?;
|
||||
let (vals, spans) = match input.parse::<syn::ExprArray>() {
|
||||
Ok(exprs) => {
|
||||
let mut vals = vec![];
|
||||
let mut spans = vec![];
|
||||
|
||||
for expr in exprs.elems.iter() {
|
||||
if let syn::Expr::Lit(syn::ExprLit {
|
||||
lit: syn::Lit::Str(ref str),
|
||||
..
|
||||
}) = expr {
|
||||
vals.push(str.value());
|
||||
spans.push(str.span());
|
||||
} else {
|
||||
return Err(syn::Error::new(expr.span(), "expected string literals"));
|
||||
}
|
||||
}
|
||||
|
||||
(vals, spans)
|
||||
},
|
||||
Err(_) => {
|
||||
let ident = input.parse::<AnyIdent>()?.0;
|
||||
(vec![ident.to_string()], vec![ident.span()])
|
||||
}
|
||||
};
|
||||
return Ok(BindgenAttr::$variant(attr_span, vals, spans))
|
||||
});
|
||||
}
|
||||
|
||||
attrgen!(parsers);
|
||||
|
||||
Err(original.error("unknown attribute"))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ConvertToAST {
|
||||
fn convert_to_ast(&mut self, opts: BindgenAttrs) -> BindgenResult<Napi>;
|
||||
fn convert_to_ast(&mut self, opts: &BindgenAttrs) -> BindgenResult<Napi>;
|
||||
}
|
||||
|
||||
pub trait ParseNapi {
|
||||
fn parse_napi(&mut self, tokens: &mut TokenStream, opts: BindgenAttrs) -> BindgenResult<Napi>;
|
||||
fn parse_napi(&mut self, tokens: &mut TokenStream, opts: &BindgenAttrs) -> BindgenResult<Napi>;
|
||||
}
|
||||
|
||||
/// This function does a few things:
|
||||
|
@ -197,44 +71,49 @@ fn find_ts_arg_type_and_remove_attribute(
|
|||
p: &mut PatType,
|
||||
ts_args_type: Option<&(&str, Span)>,
|
||||
) -> BindgenResult<Option<String>> {
|
||||
let mut ts_type_attr: Option<(usize, String)> = None;
|
||||
for (idx, attr) in p.attrs.iter().enumerate() {
|
||||
if let Ok(Meta::List(meta_list)) = attr.parse_meta() {
|
||||
if meta_list.path.get_ident() != Some(&format_ident!("napi")) {
|
||||
// If this attribute is not for `napi` ignore it.
|
||||
continue;
|
||||
}
|
||||
|
||||
if attr.path().is_ident("napi") {
|
||||
if let Some((ts_args_type, _)) = ts_args_type {
|
||||
bail_span!(
|
||||
meta_list,
|
||||
attr,
|
||||
"Found a 'ts_args_type'=\"{}\" override. Cannot use 'ts_arg_type' at the same time since they are mutually exclusive.",
|
||||
ts_args_type
|
||||
);
|
||||
}
|
||||
|
||||
let nested = meta_list.nested.first();
|
||||
|
||||
let nm = if let Some(NestedMeta::Meta(Meta::NameValue(nm))) = nested {
|
||||
nm
|
||||
} else {
|
||||
bail_span!(meta_list.nested, "Expected Name Value");
|
||||
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 Some(&format_ident!("ts_arg_type")) != nm.path.get_ident() {
|
||||
bail_span!(nm.path, "Did not find 'ts_arg_type'");
|
||||
if !left.is_ident("ts_arg_type") {
|
||||
bail_span!(left, "Expected 'ts_arg_type'");
|
||||
}
|
||||
|
||||
if let syn::Lit::Str(lit) = &nm.lit {
|
||||
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()));
|
||||
}
|
||||
_ => bail_span!(inner, "Expected assignment [ts_arg_type = \"MyType\"]"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((idx, value)) = ts_type_attr {
|
||||
p.attrs.remove(idx);
|
||||
return Ok(Some(lit.value()));
|
||||
Ok(Some(value))
|
||||
} else {
|
||||
bail_span!(nm.lit, "Expected a string literal");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_ty(mut ty: &syn::Type) -> &syn::Type {
|
||||
while let syn::Type::Group(g) = ty {
|
||||
|
@ -361,16 +240,19 @@ fn extract_doc_comments(attrs: &[syn::Attribute]) -> Vec<String> {
|
|||
.filter_map(|a| {
|
||||
// if the path segments include an ident of "doc" we know this
|
||||
// this is a doc comment
|
||||
if a.path.segments.iter().any(|s| s.ident == "doc") {
|
||||
if a.path().is_ident("doc") {
|
||||
Some(
|
||||
// We want to filter out any Puncts so just grab the Literals
|
||||
a.tokens.clone().into_iter().filter_map(|t| match t {
|
||||
TokenTree::Literal(lit) => {
|
||||
let quoted = lit.to_string();
|
||||
match &a.meta.require_name_value().unwrap().value {
|
||||
syn::Expr::Lit(ExprLit {
|
||||
lit: syn::Lit::Str(str),
|
||||
..
|
||||
}) => {
|
||||
let quoted = str.token().to_string();
|
||||
Some(try_unescape("ed).unwrap_or(quoted))
|
||||
}
|
||||
_ => None,
|
||||
}),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
None
|
||||
|
@ -496,6 +378,10 @@ fn extract_fn_closure_generics(
|
|||
));
|
||||
}
|
||||
}
|
||||
_ => errors.push(err_span! {
|
||||
bound,
|
||||
"unsupported bound in napi"
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -530,6 +416,10 @@ fn extract_fn_closure_generics(
|
|||
));
|
||||
}
|
||||
}
|
||||
_ => errors.push(err_span! {
|
||||
bound,
|
||||
"unsupported bound in napi"
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -715,7 +605,7 @@ fn napi_fn_from_decl(
|
|||
}
|
||||
|
||||
impl ParseNapi for syn::Item {
|
||||
fn parse_napi(&mut self, tokens: &mut TokenStream, opts: BindgenAttrs) -> BindgenResult<Napi> {
|
||||
fn parse_napi(&mut self, tokens: &mut TokenStream, opts: &BindgenAttrs) -> BindgenResult<Napi> {
|
||||
match self {
|
||||
syn::Item::Fn(f) => f.parse_napi(tokens, opts),
|
||||
syn::Item::Struct(s) => s.parse_napi(tokens, opts),
|
||||
|
@ -731,7 +621,7 @@ impl ParseNapi for syn::Item {
|
|||
}
|
||||
|
||||
impl ParseNapi for syn::ItemFn {
|
||||
fn parse_napi(&mut self, tokens: &mut TokenStream, opts: BindgenAttrs) -> BindgenResult<Napi> {
|
||||
fn parse_napi(&mut self, tokens: &mut TokenStream, opts: &BindgenAttrs) -> BindgenResult<Napi> {
|
||||
if opts.ts_type().is_some() {
|
||||
bail_span!(
|
||||
self,
|
||||
|
@ -751,7 +641,7 @@ impl ParseNapi for syn::ItemFn {
|
|||
}
|
||||
}
|
||||
impl ParseNapi for syn::ItemStruct {
|
||||
fn parse_napi(&mut self, tokens: &mut TokenStream, opts: BindgenAttrs) -> BindgenResult<Napi> {
|
||||
fn parse_napi(&mut self, tokens: &mut TokenStream, opts: &BindgenAttrs) -> BindgenResult<Napi> {
|
||||
if opts.ts_args_type().is_some()
|
||||
|| opts.ts_return_type().is_some()
|
||||
|| opts.skip_typescript().is_some()
|
||||
|
@ -785,7 +675,7 @@ impl ParseNapi for syn::ItemStruct {
|
|||
}
|
||||
|
||||
impl ParseNapi for syn::ItemImpl {
|
||||
fn parse_napi(&mut self, tokens: &mut TokenStream, opts: BindgenAttrs) -> BindgenResult<Napi> {
|
||||
fn parse_napi(&mut self, tokens: &mut TokenStream, opts: &BindgenAttrs) -> BindgenResult<Napi> {
|
||||
if opts.ts_args_type().is_some()
|
||||
|| opts.ts_return_type().is_some()
|
||||
|| opts.skip_typescript().is_some()
|
||||
|
@ -818,7 +708,7 @@ impl ParseNapi for syn::ItemImpl {
|
|||
}
|
||||
|
||||
impl ParseNapi for syn::ItemEnum {
|
||||
fn parse_napi(&mut self, tokens: &mut TokenStream, opts: BindgenAttrs) -> BindgenResult<Napi> {
|
||||
fn parse_napi(&mut self, tokens: &mut TokenStream, opts: &BindgenAttrs) -> BindgenResult<Napi> {
|
||||
if opts.ts_args_type().is_some()
|
||||
|| opts.ts_return_type().is_some()
|
||||
|| opts.ts_type().is_some()
|
||||
|
@ -848,7 +738,7 @@ impl ParseNapi for syn::ItemEnum {
|
|||
}
|
||||
}
|
||||
impl ParseNapi for syn::ItemConst {
|
||||
fn parse_napi(&mut self, tokens: &mut TokenStream, opts: BindgenAttrs) -> BindgenResult<Napi> {
|
||||
fn parse_napi(&mut self, tokens: &mut TokenStream, opts: &BindgenAttrs) -> BindgenResult<Napi> {
|
||||
if opts.ts_args_type().is_some()
|
||||
|| opts.ts_return_type().is_some()
|
||||
|| opts.ts_type().is_some()
|
||||
|
@ -900,10 +790,10 @@ fn fn_kind(opts: &BindgenAttrs) -> FnKind {
|
|||
}
|
||||
|
||||
impl ConvertToAST for syn::ItemFn {
|
||||
fn convert_to_ast(&mut self, opts: BindgenAttrs) -> BindgenResult<Napi> {
|
||||
fn convert_to_ast(&mut self, opts: &BindgenAttrs) -> BindgenResult<Napi> {
|
||||
let func = napi_fn_from_decl(
|
||||
&mut self.sig,
|
||||
&opts,
|
||||
opts,
|
||||
self.attrs.clone(),
|
||||
self.vis.clone(),
|
||||
None,
|
||||
|
@ -916,7 +806,7 @@ impl ConvertToAST for syn::ItemFn {
|
|||
}
|
||||
|
||||
impl ConvertToAST for syn::ItemStruct {
|
||||
fn convert_to_ast(&mut self, opts: BindgenAttrs) -> BindgenResult<Napi> {
|
||||
fn convert_to_ast(&mut self, opts: &BindgenAttrs) -> BindgenResult<Napi> {
|
||||
let mut errors = vec![];
|
||||
|
||||
let vis = self.vis.clone();
|
||||
|
@ -988,7 +878,7 @@ impl ConvertToAST for syn::ItemStruct {
|
|||
})
|
||||
}
|
||||
|
||||
record_struct(&struct_name, js_name.clone(), &opts);
|
||||
record_struct(&struct_name, js_name.clone(), opts);
|
||||
let namespace = opts.namespace().map(|(m, _)| m.to_owned());
|
||||
let implement_iterator = opts.iterator().is_some();
|
||||
GENERATOR_STRUCT.with(|inner| {
|
||||
|
@ -1021,7 +911,7 @@ impl ConvertToAST for syn::ItemStruct {
|
|||
}
|
||||
|
||||
impl ConvertToAST for syn::ItemImpl {
|
||||
fn convert_to_ast(&mut self, impl_opts: BindgenAttrs) -> BindgenResult<Napi> {
|
||||
fn convert_to_ast(&mut self, impl_opts: &BindgenAttrs) -> BindgenResult<Napi> {
|
||||
let struct_name = match get_ty(&self.self_ty) {
|
||||
syn::Type::Path(syn::TypePath {
|
||||
ref path,
|
||||
|
@ -1042,7 +932,7 @@ impl ConvertToAST for syn::ItemImpl {
|
|||
let mut iterator_return_type = None;
|
||||
for item in self.items.iter_mut() {
|
||||
if let Some(method) = match item {
|
||||
syn::ImplItem::Method(m) => Some(m),
|
||||
syn::ImplItem::Fn(m) => Some(m),
|
||||
syn::ImplItem::Type(m) => {
|
||||
if let Some((_, t, _)) = &self.trait_ {
|
||||
if let Some(PathSegment { ident, .. }) = t.segments.last() {
|
||||
|
@ -1119,19 +1009,13 @@ impl ConvertToAST for syn::ItemImpl {
|
|||
}
|
||||
|
||||
impl ConvertToAST for syn::ItemEnum {
|
||||
fn convert_to_ast(&mut self, opts: BindgenAttrs) -> BindgenResult<Napi> {
|
||||
fn convert_to_ast(&mut self, opts: &BindgenAttrs) -> BindgenResult<Napi> {
|
||||
match self.vis {
|
||||
Visibility::Public(_) => {}
|
||||
_ => bail_span!(self, "only public enum allowed"),
|
||||
}
|
||||
|
||||
self.attrs.push(Attribute {
|
||||
pound_token: Default::default(),
|
||||
style: syn::AttrStyle::Outer,
|
||||
bracket_token: Default::default(),
|
||||
path: syn::parse_quote! { derive },
|
||||
tokens: quote! { (Copy, Clone) },
|
||||
});
|
||||
self.attrs.push(parse_quote!(#[derive(Copy, Clone)]));
|
||||
|
||||
let js_name = opts
|
||||
.js_name()
|
||||
|
@ -1234,7 +1118,7 @@ impl ConvertToAST for syn::ItemEnum {
|
|||
}
|
||||
|
||||
impl ConvertToAST for syn::ItemConst {
|
||||
fn convert_to_ast(&mut self, opts: BindgenAttrs) -> BindgenResult<Napi> {
|
||||
fn convert_to_ast(&mut self, opts: &BindgenAttrs) -> BindgenResult<Napi> {
|
||||
match self.vis {
|
||||
Visibility::Public(_) => Ok(Napi {
|
||||
item: NapiItem::Const(NapiConst {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
"TS_NODE_PROJECT": "../tsconfig.json"
|
||||
},
|
||||
"workerThreads": false,
|
||||
"cache": false,
|
||||
"timeout": "5m"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
"files": [
|
||||
"__tests__/**/*.spec.{ts,cts,js,cjs,mjs}"
|
||||
],
|
||||
"cache": false,
|
||||
"timeout": "10m"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: Found a 'ts_args_type'="u: number, fn: object" override. Cannot use 'ts_arg_type' at the same time since they are mutually exclusive.
|
||||
--> tests/build_error_tests/ts_arg_type_1.rs:7:22
|
||||
--> tests/build_error_tests/ts_arg_type_1.rs:7:20
|
||||
|
|
||||
7 | pub fn add(u: u32, #[napi(ts_arg_type = "object")] f: Option<String>) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: Expected a string literal
|
||||
error: Expected 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<String>) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: Expected Name Value
|
||||
--> tests/build_error_tests/ts_arg_type_3.rs:7:27
|
||||
error: unexpected token
|
||||
--> tests/build_error_tests/ts_arg_type_3.rs:7:38
|
||||
|
|
||||
7 | pub fn add(u: u32, #[napi(ts_arg_type, not_expected)] f: Option<String>) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: Did not find 'ts_arg_type'
|
||||
error: Expected 'ts_arg_type'
|
||||
--> tests/build_error_tests/ts_arg_type_4.rs:7:27
|
||||
|
|
||||
7 | pub fn add(u: u32, #[napi(not_expected = "obj")] f: Option<String>) {
|
||||
|
|
Loading…
Reference in a new issue