feat(napi): add ts typegen skip
This commit is contained in:
parent
59a7e37901
commit
df9dc91562
11 changed files with 84 additions and 37 deletions
|
@ -361,7 +361,10 @@ async function processIntermediateTypeFile(
|
||||||
return idents
|
return idents
|
||||||
}
|
}
|
||||||
|
|
||||||
const dtsHeader = `/* eslint-disable */
|
const dtsHeader = `/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
/* auto-generated by Napi-rs */
|
||||||
|
|
||||||
export class ExternalObject<T> {
|
export class ExternalObject<T> {
|
||||||
readonly '': {
|
readonly '': {
|
||||||
|
|
|
@ -18,6 +18,7 @@ pub struct NapiFn {
|
||||||
pub js_mod: Option<String>,
|
pub js_mod: Option<String>,
|
||||||
pub ts_args_type: Option<String>,
|
pub ts_args_type: Option<String>,
|
||||||
pub ts_return_type: Option<String>,
|
pub ts_return_type: Option<String>,
|
||||||
|
pub skip_typescript: bool,
|
||||||
pub comments: Vec<String>,
|
pub comments: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +78,7 @@ pub struct NapiStructField {
|
||||||
pub getter: bool,
|
pub getter: bool,
|
||||||
pub setter: bool,
|
pub setter: bool,
|
||||||
pub comments: Vec<String>,
|
pub comments: Vec<String>,
|
||||||
|
pub skip_typescript: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -96,6 +98,7 @@ pub struct NapiEnum {
|
||||||
pub variants: Vec<NapiEnumVariant>,
|
pub variants: Vec<NapiEnumVariant>,
|
||||||
pub js_mod: Option<String>,
|
pub js_mod: Option<String>,
|
||||||
pub comments: Vec<String>,
|
pub comments: Vec<String>,
|
||||||
|
pub skip_typescript: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -113,6 +116,7 @@ pub struct NapiConst {
|
||||||
pub value: Expr,
|
pub value: Expr,
|
||||||
pub js_mod: Option<String>,
|
pub js_mod: Option<String>,
|
||||||
pub comments: Vec<String>,
|
pub comments: Vec<String>,
|
||||||
|
pub skip_typescript: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
@ -38,7 +38,7 @@ macro_rules! napi_ast_impl {
|
||||||
|
|
||||||
#[cfg(feature = "type-def")]
|
#[cfg(feature = "type-def")]
|
||||||
impl ToTypeDef for Napi {
|
impl ToTypeDef for Napi {
|
||||||
fn to_type_def(&self) -> TypeDef {
|
fn to_type_def(&self) -> Option<TypeDef> {
|
||||||
match self.item {
|
match self.item {
|
||||||
$( NapiItem::$v(ref ast) => ast.to_type_def() ),*
|
$( NapiItem::$v(ref ast) => ast.to_type_def() ),*
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ impl ToString for TypeDef {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToTypeDef {
|
pub trait ToTypeDef {
|
||||||
fn to_type_def(&self) -> TypeDef;
|
fn to_type_def(&self) -> Option<TypeDef>;
|
||||||
}
|
}
|
||||||
|
|
||||||
static KNOWN_TYPES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
|
static KNOWN_TYPES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
|
||||||
|
|
|
@ -3,9 +3,14 @@ use super::{ToTypeDef, TypeDef};
|
||||||
use crate::{js_doc_from_comments, ty_to_ts_type, typegen::add_alias, NapiConst};
|
use crate::{js_doc_from_comments, ty_to_ts_type, typegen::add_alias, NapiConst};
|
||||||
|
|
||||||
impl ToTypeDef for NapiConst {
|
impl ToTypeDef for NapiConst {
|
||||||
fn to_type_def(&self) -> TypeDef {
|
fn to_type_def(&self) -> Option<TypeDef> {
|
||||||
|
if self.skip_typescript {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
add_alias(self.name.to_string(), self.js_name.to_string());
|
add_alias(self.name.to_string(), self.js_name.to_string());
|
||||||
TypeDef {
|
|
||||||
|
Some(TypeDef {
|
||||||
kind: "const".to_owned(),
|
kind: "const".to_owned(),
|
||||||
name: self.js_name.to_owned(),
|
name: self.js_name.to_owned(),
|
||||||
def: format!(
|
def: format!(
|
||||||
|
@ -15,6 +20,6 @@ impl ToTypeDef for NapiConst {
|
||||||
),
|
),
|
||||||
js_mod: self.js_mod.to_owned(),
|
js_mod: self.js_mod.to_owned(),
|
||||||
js_doc: js_doc_from_comments(&self.comments),
|
js_doc: js_doc_from_comments(&self.comments),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,15 +2,20 @@ use super::{add_alias, ToTypeDef, TypeDef};
|
||||||
use crate::{js_doc_from_comments, NapiEnum};
|
use crate::{js_doc_from_comments, NapiEnum};
|
||||||
|
|
||||||
impl ToTypeDef for NapiEnum {
|
impl ToTypeDef for NapiEnum {
|
||||||
fn to_type_def(&self) -> TypeDef {
|
fn to_type_def(&self) -> Option<TypeDef> {
|
||||||
|
if self.skip_typescript {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
add_alias(self.name.to_string(), self.js_name.to_string());
|
add_alias(self.name.to_string(), self.js_name.to_string());
|
||||||
TypeDef {
|
|
||||||
|
Some(TypeDef {
|
||||||
kind: "enum".to_owned(),
|
kind: "enum".to_owned(),
|
||||||
name: self.js_name.to_owned(),
|
name: self.js_name.to_owned(),
|
||||||
def: self.gen_ts_variants(),
|
def: self.gen_ts_variants(),
|
||||||
js_doc: js_doc_from_comments(&self.comments),
|
js_doc: js_doc_from_comments(&self.comments),
|
||||||
js_mod: self.js_mod.to_owned(),
|
js_mod: self.js_mod.to_owned(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,11 @@ use super::{ty_to_ts_type, ToTypeDef, TypeDef};
|
||||||
use crate::{js_doc_from_comments, CallbackArg, FnKind, NapiFn};
|
use crate::{js_doc_from_comments, CallbackArg, FnKind, NapiFn};
|
||||||
|
|
||||||
impl ToTypeDef for NapiFn {
|
impl ToTypeDef for NapiFn {
|
||||||
fn to_type_def(&self) -> TypeDef {
|
fn to_type_def(&self) -> Option<TypeDef> {
|
||||||
|
if self.skip_typescript {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let def = format!(
|
let def = format!(
|
||||||
r#"{prefix} {name}({args}){ret}"#,
|
r#"{prefix} {name}({args}){ret}"#,
|
||||||
prefix = self.gen_ts_func_prefix(),
|
prefix = self.gen_ts_func_prefix(),
|
||||||
|
@ -22,13 +26,13 @@ impl ToTypeDef for NapiFn {
|
||||||
.unwrap_or_else(|| self.gen_ts_func_ret()),
|
.unwrap_or_else(|| self.gen_ts_func_ret()),
|
||||||
);
|
);
|
||||||
|
|
||||||
TypeDef {
|
Some(TypeDef {
|
||||||
kind: "fn".to_owned(),
|
kind: "fn".to_owned(),
|
||||||
name: self.js_name.clone(),
|
name: self.js_name.clone(),
|
||||||
def,
|
def,
|
||||||
js_mod: self.js_mod.to_owned(),
|
js_mod: self.js_mod.to_owned(),
|
||||||
js_doc: js_doc_from_comments(&self.comments),
|
js_doc: js_doc_from_comments(&self.comments),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,14 @@ thread_local! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToTypeDef for NapiStruct {
|
impl ToTypeDef for NapiStruct {
|
||||||
fn to_type_def(&self) -> TypeDef {
|
fn to_type_def(&self) -> Option<TypeDef> {
|
||||||
CLASS_STRUCTS.with(|c| {
|
CLASS_STRUCTS.with(|c| {
|
||||||
c.borrow_mut()
|
c.borrow_mut()
|
||||||
.insert(self.name.to_string(), self.js_name.clone());
|
.insert(self.name.to_string(), self.js_name.clone());
|
||||||
});
|
});
|
||||||
add_alias(self.name.to_string(), self.js_name.to_string());
|
add_alias(self.name.to_string(), self.js_name.to_string());
|
||||||
TypeDef {
|
|
||||||
|
Some(TypeDef {
|
||||||
kind: String::from(if self.kind == NapiStructKind::Object {
|
kind: String::from(if self.kind == NapiStructKind::Object {
|
||||||
"interface"
|
"interface"
|
||||||
} else {
|
} else {
|
||||||
|
@ -26,36 +27,42 @@ impl ToTypeDef for NapiStruct {
|
||||||
def: self.gen_ts_class(),
|
def: self.gen_ts_class(),
|
||||||
js_mod: self.js_mod.to_owned(),
|
js_mod: self.js_mod.to_owned(),
|
||||||
js_doc: js_doc_from_comments(&self.comments),
|
js_doc: js_doc_from_comments(&self.comments),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToTypeDef for NapiImpl {
|
impl ToTypeDef for NapiImpl {
|
||||||
fn to_type_def(&self) -> TypeDef {
|
fn to_type_def(&self) -> Option<TypeDef> {
|
||||||
if let Some(output_type) = &self.task_output_type {
|
if let Some(output_type) = &self.task_output_type {
|
||||||
TASK_STRUCTS.with(|t| {
|
TASK_STRUCTS.with(|t| {
|
||||||
t.borrow_mut()
|
t.borrow_mut()
|
||||||
.insert(self.js_name.clone(), ty_to_ts_type(output_type, false).0);
|
.insert(self.js_name.clone(), ty_to_ts_type(output_type, false).0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
TypeDef {
|
|
||||||
|
Some(TypeDef {
|
||||||
kind: "impl".to_owned(),
|
kind: "impl".to_owned(),
|
||||||
name: self.js_name.to_owned(),
|
name: self.js_name.to_owned(),
|
||||||
def: self
|
def: self
|
||||||
.items
|
.items
|
||||||
.iter()
|
.iter()
|
||||||
.map(|f| {
|
.filter_map(|f| {
|
||||||
format!(
|
if f.skip_typescript {
|
||||||
"{}{}",
|
None
|
||||||
js_doc_from_comments(&f.comments),
|
} else {
|
||||||
f.to_type_def().def
|
Some(format!(
|
||||||
)
|
"{}{}",
|
||||||
|
js_doc_from_comments(&f.comments),
|
||||||
|
f.to_type_def()
|
||||||
|
.map_or(String::default(), |type_def| type_def.def)
|
||||||
|
))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\\n"),
|
.join("\\n"),
|
||||||
js_mod: self.js_mod.to_owned(),
|
js_mod: self.js_mod.to_owned(),
|
||||||
js_doc: "".to_string(),
|
js_doc: "".to_string(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +76,10 @@ impl NapiStruct {
|
||||||
.map(|f| {
|
.map(|f| {
|
||||||
let mut field_str = String::from("");
|
let mut field_str = String::from("");
|
||||||
|
|
||||||
|
if f.skip_typescript {
|
||||||
|
return field_str;
|
||||||
|
}
|
||||||
|
|
||||||
if !f.comments.is_empty() {
|
if !f.comments.is_empty() {
|
||||||
field_str.push_str(&js_doc_from_comments(&f.comments))
|
field_str.push_str(&js_doc_from_comments(&f.comments))
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,15 +141,19 @@ fn expand(attr: TokenStream, input: TokenStream) -> BindgenResult<TokenStream> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "type-def", not(feature = "noop")))]
|
#[cfg(all(feature = "type-def", not(feature = "noop")))]
|
||||||
fn output_type_def(type_def_file: String, type_def: TypeDef) -> IOResult<()> {
|
fn output_type_def(type_def_file: String, type_def: Option<TypeDef>) -> IOResult<()> {
|
||||||
let file = fs::OpenOptions::new()
|
if type_def.is_some() {
|
||||||
.append(true)
|
let file = fs::OpenOptions::new()
|
||||||
.create(true)
|
.append(true)
|
||||||
.open(type_def_file)?;
|
.create(true)
|
||||||
|
.open(type_def_file)?;
|
||||||
|
|
||||||
let mut writer = BufWriter::<fs::File>::new(file);
|
let mut writer = BufWriter::<fs::File>::new(file);
|
||||||
writer.write_all(type_def.to_string().as_bytes())?;
|
writer.write_all(type_def.unwrap().to_string().as_bytes())?;
|
||||||
writer.write_all("\n".as_bytes())
|
writer.write_all("\n".as_bytes())
|
||||||
|
} else {
|
||||||
|
IOResult::Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "compat-mode")]
|
#[cfg(feature = "compat-mode")]
|
||||||
|
|
|
@ -58,7 +58,7 @@ macro_rules! attrgen {
|
||||||
// impl later
|
// impl later
|
||||||
// (inspectable, Inspectable(Span)),
|
// (inspectable, Inspectable(Span)),
|
||||||
// (typescript_custom_section, TypescriptCustomSection(Span)),
|
// (typescript_custom_section, TypescriptCustomSection(Span)),
|
||||||
// (skip_typescript, SkipTypescript(Span)),
|
(skip_typescript, SkipTypescript(Span)),
|
||||||
// (getter_with_clone, GetterWithClone(Span)),
|
// (getter_with_clone, GetterWithClone(Span)),
|
||||||
|
|
||||||
// For testing purposes only.
|
// For testing purposes only.
|
||||||
|
|
|
@ -578,6 +578,7 @@ fn napi_fn_from_decl(
|
||||||
js_mod: opts.namespace().map(|(m, _)| m.to_owned()),
|
js_mod: opts.namespace().map(|(m, _)| m.to_owned()),
|
||||||
ts_args_type: opts.ts_args_type().map(|(m, _)| m.to_owned()),
|
ts_args_type: opts.ts_args_type().map(|(m, _)| m.to_owned()),
|
||||||
ts_return_type: opts.ts_return_type().map(|(m, _)| m.to_owned()),
|
ts_return_type: opts.ts_return_type().map(|(m, _)| m.to_owned()),
|
||||||
|
skip_typescript: opts.skip_typescript().is_some(),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -606,10 +607,13 @@ impl ParseNapi for syn::ItemFn {
|
||||||
}
|
}
|
||||||
impl ParseNapi for syn::ItemStruct {
|
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() {
|
if opts.ts_args_type().is_some()
|
||||||
|
|| opts.ts_return_type().is_some()
|
||||||
|
|| opts.skip_typescript().is_some()
|
||||||
|
{
|
||||||
bail_span!(
|
bail_span!(
|
||||||
self,
|
self,
|
||||||
"#[napi] can't be applied to a struct with #[napi(ts_args_type)] or #[napi(ts_return_type)]"
|
"#[napi] can't be applied to a struct with #[napi(ts_args_type)] or #[napi(ts_return_type)] or #[napi(skip_typescript)]"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let napi = self.convert_to_ast(opts);
|
let napi = self.convert_to_ast(opts);
|
||||||
|
@ -620,10 +624,13 @@ impl ParseNapi for syn::ItemStruct {
|
||||||
}
|
}
|
||||||
impl ParseNapi for syn::ItemImpl {
|
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() {
|
if opts.ts_args_type().is_some()
|
||||||
|
|| opts.ts_return_type().is_some()
|
||||||
|
|| opts.skip_typescript().is_some()
|
||||||
|
{
|
||||||
bail_span!(
|
bail_span!(
|
||||||
self,
|
self,
|
||||||
"#[napi] can't be applied to impl with #[napi(ts_args_type)] or #[napi(ts_return_type)]"
|
"#[napi] can't be applied to impl with #[napi(ts_args_type)] or #[napi(ts_return_type)] or #[napi(skip_typescript)]"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// #[napi] macro will be remove from impl items after converted to ast
|
// #[napi] macro will be remove from impl items after converted to ast
|
||||||
|
@ -751,6 +758,7 @@ impl ConvertToAST for syn::ItemStruct {
|
||||||
|
|
||||||
let ignored = field_opts.skip().is_some();
|
let ignored = field_opts.skip().is_some();
|
||||||
let readonly = field_opts.readonly().is_some();
|
let readonly = field_opts.readonly().is_some();
|
||||||
|
let skip_typescript = field_opts.skip_typescript().is_some();
|
||||||
|
|
||||||
fields.push(NapiStructField {
|
fields.push(NapiStructField {
|
||||||
name,
|
name,
|
||||||
|
@ -759,6 +767,7 @@ impl ConvertToAST for syn::ItemStruct {
|
||||||
getter: !ignored,
|
getter: !ignored,
|
||||||
setter: !(ignored || readonly),
|
setter: !(ignored || readonly),
|
||||||
comments: extract_doc_comments(&field.attrs),
|
comments: extract_doc_comments(&field.attrs),
|
||||||
|
skip_typescript,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -943,6 +952,7 @@ impl ConvertToAST for syn::ItemEnum {
|
||||||
variants,
|
variants,
|
||||||
js_mod: opts.namespace().map(|(m, _)| m.to_owned()),
|
js_mod: opts.namespace().map(|(m, _)| m.to_owned()),
|
||||||
comments: extract_doc_comments(&self.attrs),
|
comments: extract_doc_comments(&self.attrs),
|
||||||
|
skip_typescript: opts.skip_typescript().is_some(),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -961,6 +971,7 @@ impl ConvertToAST for syn::ItemConst {
|
||||||
value: *self.expr.clone(),
|
value: *self.expr.clone(),
|
||||||
js_mod: opts.namespace().map(|(m, _)| m.to_owned()),
|
js_mod: opts.namespace().map(|(m, _)| m.to_owned()),
|
||||||
comments: extract_doc_comments(&self.attrs),
|
comments: extract_doc_comments(&self.attrs),
|
||||||
|
skip_typescript: opts.skip_typescript().is_some(),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
_ => bail_span!(self, "only public const allowed"),
|
_ => bail_span!(self, "only public const allowed"),
|
||||||
|
|
Loading…
Reference in a new issue