mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-04-28 23:22:16 +00:00
Add skip_typescript attribute to prevent .d.ts emit (#2016)
* Add skip_typescript attribute to prevent .d.ts emit * Add guide page for typescript attribute
This commit is contained in:
parent
3f4acc453b
commit
7ffb5ed70c
@ -221,6 +221,7 @@ pub struct Function {
|
|||||||
pub rust_attrs: Vec<syn::Attribute>,
|
pub rust_attrs: Vec<syn::Attribute>,
|
||||||
pub rust_vis: syn::Visibility,
|
pub rust_vis: syn::Visibility,
|
||||||
pub r#async: bool,
|
pub r#async: bool,
|
||||||
|
pub generate_typescript: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||||
@ -231,6 +232,7 @@ pub struct Struct {
|
|||||||
pub fields: Vec<StructField>,
|
pub fields: Vec<StructField>,
|
||||||
pub comments: Vec<String>,
|
pub comments: Vec<String>,
|
||||||
pub is_inspectable: bool,
|
pub is_inspectable: bool,
|
||||||
|
pub generate_typescript: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||||
@ -243,6 +245,7 @@ pub struct StructField {
|
|||||||
pub getter: Ident,
|
pub getter: Ident,
|
||||||
pub setter: Ident,
|
pub setter: Ident,
|
||||||
pub comments: Vec<String>,
|
pub comments: Vec<String>,
|
||||||
|
pub generate_typescript: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||||
@ -252,6 +255,7 @@ pub struct Enum {
|
|||||||
pub variants: Vec<Variant>,
|
pub variants: Vec<Variant>,
|
||||||
pub comments: Vec<String>,
|
pub comments: Vec<String>,
|
||||||
pub hole: u32,
|
pub hole: u32,
|
||||||
|
pub generate_typescript: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||||
|
@ -206,6 +206,7 @@ fn shared_function<'a>(func: &'a ast::Function, _intern: &'a Interner) -> Functi
|
|||||||
Function {
|
Function {
|
||||||
arg_names,
|
arg_names,
|
||||||
name: &func.name,
|
name: &func.name,
|
||||||
|
generate_typescript: func.generate_typescript,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,6 +219,7 @@ fn shared_enum<'a>(e: &'a ast::Enum, intern: &'a Interner) -> Enum<'a> {
|
|||||||
.map(|v| shared_variant(v, intern))
|
.map(|v| shared_variant(v, intern))
|
||||||
.collect(),
|
.collect(),
|
||||||
comments: e.comments.iter().map(|s| &**s).collect(),
|
comments: e.comments.iter().map(|s| &**s).collect(),
|
||||||
|
generate_typescript: e.generate_typescript,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,6 +309,7 @@ fn shared_struct<'a>(s: &'a ast::Struct, intern: &'a Interner) -> Struct<'a> {
|
|||||||
.collect(),
|
.collect(),
|
||||||
comments: s.comments.iter().map(|s| &**s).collect(),
|
comments: s.comments.iter().map(|s| &**s).collect(),
|
||||||
is_inspectable: s.is_inspectable,
|
is_inspectable: s.is_inspectable,
|
||||||
|
generate_typescript: s.generate_typescript,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,6 +321,7 @@ fn shared_struct_field<'a>(s: &'a ast::StructField, intern: &'a Interner) -> Str
|
|||||||
},
|
},
|
||||||
readonly: s.readonly,
|
readonly: s.readonly,
|
||||||
comments: s.comments.iter().map(|s| &**s).collect(),
|
comments: s.comments.iter().map(|s| &**s).collect(),
|
||||||
|
generate_typescript: s.generate_typescript,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ impl<'a> Context<'a> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
export_name: &str,
|
export_name: &str,
|
||||||
contents: &str,
|
contents: &str,
|
||||||
comments: Option<String>,
|
comments: Option<&str>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let definition_name = generate_identifier(export_name, &mut self.defined_identifiers);
|
let definition_name = generate_identifier(export_name, &mut self.defined_identifiers);
|
||||||
if contents.starts_with("class") && definition_name != export_name {
|
if contents.starts_with("class") && definition_name != export_name {
|
||||||
@ -119,9 +119,8 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let contents = contents.trim();
|
let contents = contents.trim();
|
||||||
if let Some(ref c) = comments {
|
if let Some(c) = comments {
|
||||||
self.globals.push_str(c);
|
self.globals.push_str(c);
|
||||||
self.typescript.push_str(c);
|
|
||||||
}
|
}
|
||||||
let global = match self.config.mode {
|
let global = match self.config.mode {
|
||||||
OutputMode::Node {
|
OutputMode::Node {
|
||||||
@ -804,7 +803,7 @@ impl<'a> Context<'a> {
|
|||||||
dst.push_str("}\n");
|
dst.push_str("}\n");
|
||||||
ts_dst.push_str("}\n");
|
ts_dst.push_str("}\n");
|
||||||
|
|
||||||
self.export(&name, &dst, Some(class.comments.clone()))?;
|
self.export(&name, &dst, Some(&class.comments))?;
|
||||||
self.typescript.push_str(&ts_dst);
|
self.typescript.push_str(&ts_dst);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -2153,41 +2152,58 @@ impl<'a> Context<'a> {
|
|||||||
// on what's being exported.
|
// on what's being exported.
|
||||||
match kind {
|
match kind {
|
||||||
Kind::Export(export) => {
|
Kind::Export(export) => {
|
||||||
|
let ts_sig = match export.generate_typescript {
|
||||||
|
true => Some(ts_sig.as_str()),
|
||||||
|
false => None,
|
||||||
|
};
|
||||||
|
|
||||||
let docs = format_doc_comments(&export.comments, Some(js_doc));
|
let docs = format_doc_comments(&export.comments, Some(js_doc));
|
||||||
match &export.kind {
|
match &export.kind {
|
||||||
AuxExportKind::Function(name) => {
|
AuxExportKind::Function(name) => {
|
||||||
self.export(&name, &format!("function{}", code), Some(docs))?;
|
if let Some(ts_sig) = ts_sig {
|
||||||
self.globals.push_str("\n");
|
self.typescript.push_str(&docs);
|
||||||
self.typescript.push_str("export function ");
|
self.typescript.push_str("export function ");
|
||||||
self.typescript.push_str(&name);
|
self.typescript.push_str(&name);
|
||||||
self.typescript.push_str(&ts_sig);
|
self.typescript.push_str(ts_sig);
|
||||||
self.typescript.push_str(";\n");
|
self.typescript.push_str(";\n");
|
||||||
}
|
}
|
||||||
|
self.export(&name, &format!("function{}", code), Some(&docs))?;
|
||||||
|
self.globals.push_str("\n");
|
||||||
|
}
|
||||||
AuxExportKind::Constructor(class) => {
|
AuxExportKind::Constructor(class) => {
|
||||||
let exported = require_class(&mut self.exported_classes, class);
|
let exported = require_class(&mut self.exported_classes, class);
|
||||||
if exported.has_constructor {
|
if exported.has_constructor {
|
||||||
bail!("found duplicate constructor for class `{}`", class);
|
bail!("found duplicate constructor for class `{}`", class);
|
||||||
}
|
}
|
||||||
exported.has_constructor = true;
|
exported.has_constructor = true;
|
||||||
exported.push(&docs, "constructor", "", &code, &ts_sig);
|
exported.push(&docs, "constructor", "", &code, ts_sig);
|
||||||
}
|
}
|
||||||
AuxExportKind::Getter { class, field } => {
|
AuxExportKind::Getter { class, field } => {
|
||||||
let ret_ty = ts_ret_ty.unwrap();
|
let ret_ty = match export.generate_typescript {
|
||||||
|
true => match &ts_ret_ty {
|
||||||
|
Some(s) => Some(s.as_str()),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
false => None,
|
||||||
|
};
|
||||||
let exported = require_class(&mut self.exported_classes, class);
|
let exported = require_class(&mut self.exported_classes, class);
|
||||||
exported.push_getter(&docs, field, &code, &ret_ty);
|
exported.push_getter(&docs, field, &code, ret_ty);
|
||||||
}
|
}
|
||||||
AuxExportKind::Setter { class, field } => {
|
AuxExportKind::Setter { class, field } => {
|
||||||
let arg_ty = ts_arg_tys[0].clone();
|
let arg_ty = match export.generate_typescript {
|
||||||
|
true => Some(ts_arg_tys[0].as_str()),
|
||||||
|
false => None,
|
||||||
|
};
|
||||||
let exported = require_class(&mut self.exported_classes, class);
|
let exported = require_class(&mut self.exported_classes, class);
|
||||||
exported.push_setter(&docs, field, &code, &arg_ty, might_be_optional_field);
|
exported.push_setter(&docs, field, &code, arg_ty, might_be_optional_field);
|
||||||
}
|
}
|
||||||
AuxExportKind::StaticFunction { class, name } => {
|
AuxExportKind::StaticFunction { class, name } => {
|
||||||
let exported = require_class(&mut self.exported_classes, class);
|
let exported = require_class(&mut self.exported_classes, class);
|
||||||
exported.push(&docs, name, "static ", &code, &ts_sig);
|
exported.push(&docs, name, "static ", &code, ts_sig);
|
||||||
}
|
}
|
||||||
AuxExportKind::Method { class, name, .. } => {
|
AuxExportKind::Method { class, name, .. } => {
|
||||||
let exported = require_class(&mut self.exported_classes, class);
|
let exported = require_class(&mut self.exported_classes, class);
|
||||||
exported.push(&docs, name, "", &code, &ts_sig);
|
exported.push(&docs, name, "", &code, ts_sig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2865,19 +2881,27 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generate_enum(&mut self, enum_: &AuxEnum) -> Result<(), Error> {
|
fn generate_enum(&mut self, enum_: &AuxEnum) -> Result<(), Error> {
|
||||||
|
let docs = format_doc_comments(&enum_.comments, None);
|
||||||
let mut variants = String::new();
|
let mut variants = String::new();
|
||||||
|
|
||||||
|
if enum_.generate_typescript {
|
||||||
|
self.typescript.push_str(&docs);
|
||||||
self.typescript
|
self.typescript
|
||||||
.push_str(&format!("export enum {} {{", enum_.name));
|
.push_str(&format!("export enum {} {{", enum_.name));
|
||||||
|
}
|
||||||
for (name, value) in enum_.variants.iter() {
|
for (name, value) in enum_.variants.iter() {
|
||||||
variants.push_str(&format!("{}:{},", name, value));
|
variants.push_str(&format!("{}:{},", name, value));
|
||||||
|
if enum_.generate_typescript {
|
||||||
self.typescript.push_str(&format!("\n {},", name));
|
self.typescript.push_str(&format!("\n {},", name));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if enum_.generate_typescript {
|
||||||
self.typescript.push_str("\n}\n");
|
self.typescript.push_str("\n}\n");
|
||||||
|
}
|
||||||
self.export(
|
self.export(
|
||||||
&enum_.name,
|
&enum_.name,
|
||||||
&format!("Object.freeze({{ {} }})", variants),
|
&format!("Object.freeze({{ {} }})", variants),
|
||||||
Some(format_doc_comments(&enum_.comments, None)),
|
Some(&docs),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -3163,12 +3187,20 @@ fn require_class<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ExportedClass {
|
impl ExportedClass {
|
||||||
fn push(&mut self, docs: &str, function_name: &str, function_prefix: &str, js: &str, ts: &str) {
|
fn push(
|
||||||
|
&mut self,
|
||||||
|
docs: &str,
|
||||||
|
function_name: &str,
|
||||||
|
function_prefix: &str,
|
||||||
|
js: &str,
|
||||||
|
ts: Option<&str>,
|
||||||
|
) {
|
||||||
self.contents.push_str(docs);
|
self.contents.push_str(docs);
|
||||||
self.contents.push_str(function_prefix);
|
self.contents.push_str(function_prefix);
|
||||||
self.contents.push_str(function_name);
|
self.contents.push_str(function_name);
|
||||||
self.contents.push_str(js);
|
self.contents.push_str(js);
|
||||||
self.contents.push_str("\n");
|
self.contents.push_str("\n");
|
||||||
|
if let Some(ts) = ts {
|
||||||
self.typescript.push_str(docs);
|
self.typescript.push_str(docs);
|
||||||
self.typescript.push_str(" ");
|
self.typescript.push_str(" ");
|
||||||
self.typescript.push_str(function_prefix);
|
self.typescript.push_str(function_prefix);
|
||||||
@ -3176,11 +3208,15 @@ impl ExportedClass {
|
|||||||
self.typescript.push_str(ts);
|
self.typescript.push_str(ts);
|
||||||
self.typescript.push_str(";\n");
|
self.typescript.push_str(";\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Used for adding a getter to a class, mainly to ensure that TypeScript
|
/// Used for adding a getter to a class, mainly to ensure that TypeScript
|
||||||
/// generation is handled specially.
|
/// generation is handled specially.
|
||||||
fn push_getter(&mut self, docs: &str, field: &str, js: &str, ret_ty: &str) {
|
fn push_getter(&mut self, docs: &str, field: &str, js: &str, ret_ty: Option<&str>) {
|
||||||
self.push_accessor(docs, field, js, "get ", ret_ty);
|
self.push_accessor(docs, field, js, "get ");
|
||||||
|
if let Some(ret_ty) = ret_ty {
|
||||||
|
self.push_accessor_ts(field, ret_ty);
|
||||||
|
}
|
||||||
self.readable_properties.push(field.to_string());
|
self.readable_properties.push(field.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3191,28 +3227,18 @@ impl ExportedClass {
|
|||||||
docs: &str,
|
docs: &str,
|
||||||
field: &str,
|
field: &str,
|
||||||
js: &str,
|
js: &str,
|
||||||
ret_ty: &str,
|
ret_ty: Option<&str>,
|
||||||
might_be_optional_field: bool,
|
might_be_optional_field: bool,
|
||||||
) {
|
) {
|
||||||
let (has_setter, is_optional) = self.push_accessor(docs, field, js, "set ", ret_ty);
|
self.push_accessor(docs, field, js, "set ");
|
||||||
|
if let Some(ret_ty) = ret_ty {
|
||||||
|
let (has_setter, is_optional) = self.push_accessor_ts(field, ret_ty);
|
||||||
*has_setter = true;
|
*has_setter = true;
|
||||||
*is_optional = might_be_optional_field;
|
*is_optional = might_be_optional_field;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn push_accessor(
|
fn push_accessor_ts(&mut self, field: &str, ret_ty: &str) -> (&mut bool, &mut bool) {
|
||||||
&mut self,
|
|
||||||
docs: &str,
|
|
||||||
field: &str,
|
|
||||||
js: &str,
|
|
||||||
prefix: &str,
|
|
||||||
ret_ty: &str,
|
|
||||||
) -> (&mut bool, &mut bool) {
|
|
||||||
self.contents.push_str(docs);
|
|
||||||
self.contents.push_str(prefix);
|
|
||||||
self.contents.push_str(field);
|
|
||||||
self.contents.push_str(js);
|
|
||||||
self.contents.push_str("\n");
|
|
||||||
|
|
||||||
let (ty, has_setter, is_optional) = self
|
let (ty, has_setter, is_optional) = self
|
||||||
.typescript_fields
|
.typescript_fields
|
||||||
.entry(field.to_string())
|
.entry(field.to_string())
|
||||||
@ -3221,6 +3247,14 @@ impl ExportedClass {
|
|||||||
*ty = ret_ty.to_string();
|
*ty = ret_ty.to_string();
|
||||||
(has_setter, is_optional)
|
(has_setter, is_optional)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn push_accessor(&mut self, docs: &str, field: &str, js: &str, prefix: &str) {
|
||||||
|
self.contents.push_str(docs);
|
||||||
|
self.contents.push_str(prefix);
|
||||||
|
self.contents.push_str(field);
|
||||||
|
self.contents.push_str(js);
|
||||||
|
self.contents.push_str("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -454,6 +454,7 @@ impl<'a> Context<'a> {
|
|||||||
comments: concatenate_comments(&export.comments),
|
comments: concatenate_comments(&export.comments),
|
||||||
arg_names: Some(export.function.arg_names),
|
arg_names: Some(export.function.arg_names),
|
||||||
kind,
|
kind,
|
||||||
|
generate_typescript: export.function.generate_typescript,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -767,6 +768,7 @@ impl<'a> Context<'a> {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|v| (v.name.to_string(), v.value))
|
.map(|v| (v.name.to_string(), v.value))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
generate_typescript: enum_.generate_typescript,
|
||||||
};
|
};
|
||||||
self.aux.enums.push(aux);
|
self.aux.enums.push(aux);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -799,6 +801,7 @@ impl<'a> Context<'a> {
|
|||||||
class: struct_.name.to_string(),
|
class: struct_.name.to_string(),
|
||||||
field: field.name.to_string(),
|
field: field.name.to_string(),
|
||||||
},
|
},
|
||||||
|
generate_typescript: field.generate_typescript,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -824,6 +827,7 @@ impl<'a> Context<'a> {
|
|||||||
class: struct_.name.to_string(),
|
class: struct_.name.to_string(),
|
||||||
field: field.name.to_string(),
|
field: field.name.to_string(),
|
||||||
},
|
},
|
||||||
|
generate_typescript: field.generate_typescript,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -831,6 +835,7 @@ impl<'a> Context<'a> {
|
|||||||
name: struct_.name.to_string(),
|
name: struct_.name.to_string(),
|
||||||
comments: concatenate_comments(&struct_.comments),
|
comments: concatenate_comments(&struct_.comments),
|
||||||
is_inspectable: struct_.is_inspectable,
|
is_inspectable: struct_.is_inspectable,
|
||||||
|
generate_typescript: struct_.generate_typescript,
|
||||||
};
|
};
|
||||||
self.aux.structs.push(aux);
|
self.aux.structs.push(aux);
|
||||||
|
|
||||||
@ -1048,6 +1053,7 @@ impl<'a> Context<'a> {
|
|||||||
comments: String::new(),
|
comments: String::new(),
|
||||||
arg_names: None,
|
arg_names: None,
|
||||||
kind,
|
kind,
|
||||||
|
generate_typescript: true,
|
||||||
};
|
};
|
||||||
assert!(self.aux.export_map.insert(id, export).is_none());
|
assert!(self.aux.export_map.insert(id, export).is_none());
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,8 @@ pub struct AuxExport {
|
|||||||
pub arg_names: Option<Vec<String>>,
|
pub arg_names: Option<Vec<String>>,
|
||||||
/// What kind of function this is and where it shows up
|
/// What kind of function this is and where it shows up
|
||||||
pub kind: AuxExportKind,
|
pub kind: AuxExportKind,
|
||||||
|
/// Whether typescript bindings should be generated for this export.
|
||||||
|
pub generate_typescript: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All possible kinds of exports from a wasm module.
|
/// All possible kinds of exports from a wasm module.
|
||||||
@ -131,7 +133,10 @@ pub struct AuxEnum {
|
|||||||
/// The copied Rust comments to forward to JS
|
/// The copied Rust comments to forward to JS
|
||||||
pub comments: String,
|
pub comments: String,
|
||||||
/// A list of variants with their name and value
|
/// A list of variants with their name and value
|
||||||
|
/// and whether typescript bindings should be generated for each variant
|
||||||
pub variants: Vec<(String, u32)>,
|
pub variants: Vec<(String, u32)>,
|
||||||
|
/// Whether typescript bindings should be generated for this enum.
|
||||||
|
pub generate_typescript: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -142,6 +147,8 @@ pub struct AuxStruct {
|
|||||||
pub comments: String,
|
pub comments: String,
|
||||||
/// Whether to generate helper methods for inspecting the class
|
/// Whether to generate helper methods for inspecting the class
|
||||||
pub is_inspectable: bool,
|
pub is_inspectable: bool,
|
||||||
|
/// Whether typescript bindings should be generated for this struct.
|
||||||
|
pub generate_typescript: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All possible types of imports that can be imported by a wasm module.
|
/// All possible types of imports that can be imported by a wasm module.
|
||||||
|
@ -51,6 +51,7 @@ macro_rules! attrgen {
|
|||||||
(vendor_prefix, VendorPrefix(Span, Ident)),
|
(vendor_prefix, VendorPrefix(Span, Ident)),
|
||||||
(variadic, Variadic(Span)),
|
(variadic, Variadic(Span)),
|
||||||
(typescript_custom_section, TypescriptCustomSection(Span)),
|
(typescript_custom_section, TypescriptCustomSection(Span)),
|
||||||
|
(skip_typescript, SkipTypescript(Span)),
|
||||||
(start, Start(Span)),
|
(start, Start(Span)),
|
||||||
(skip, Skip(Span)),
|
(skip, Skip(Span)),
|
||||||
(typescript_type, TypeScriptType(Span, String, Span)),
|
(typescript_type, TypeScriptType(Span, String, Span)),
|
||||||
@ -354,9 +355,11 @@ impl<'a> ConvertToAst<BindgenAttrs> for &'a mut syn::ItemStruct {
|
|||||||
getter: Ident::new(&getter, Span::call_site()),
|
getter: Ident::new(&getter, Span::call_site()),
|
||||||
setter: Ident::new(&setter, Span::call_site()),
|
setter: Ident::new(&setter, Span::call_site()),
|
||||||
comments,
|
comments,
|
||||||
|
generate_typescript: attrs.skip_typescript().is_none(),
|
||||||
});
|
});
|
||||||
attrs.check_used()?;
|
attrs.check_used()?;
|
||||||
}
|
}
|
||||||
|
let generate_typescript = attrs.skip_typescript().is_none();
|
||||||
let comments: Vec<String> = extract_doc_comments(&self.attrs);
|
let comments: Vec<String> = extract_doc_comments(&self.attrs);
|
||||||
attrs.check_used()?;
|
attrs.check_used()?;
|
||||||
Ok(ast::Struct {
|
Ok(ast::Struct {
|
||||||
@ -365,6 +368,7 @@ impl<'a> ConvertToAst<BindgenAttrs> for &'a mut syn::ItemStruct {
|
|||||||
fields,
|
fields,
|
||||||
comments,
|
comments,
|
||||||
is_inspectable,
|
is_inspectable,
|
||||||
|
generate_typescript,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -720,6 +724,7 @@ fn function_from_decl(
|
|||||||
rust_attrs: attrs,
|
rust_attrs: attrs,
|
||||||
rust_vis: vis,
|
rust_vis: vis,
|
||||||
r#async: sig.asyncness.is_some(),
|
r#async: sig.asyncness.is_some(),
|
||||||
|
generate_typescript: opts.skip_typescript().is_none(),
|
||||||
},
|
},
|
||||||
method_self,
|
method_self,
|
||||||
))
|
))
|
||||||
@ -798,11 +803,12 @@ impl<'a> MacroParse<(Option<BindgenAttrs>, &'a mut TokenStream)> for syn::Item {
|
|||||||
};
|
};
|
||||||
f.macro_parse(program, opts)?;
|
f.macro_parse(program, opts)?;
|
||||||
}
|
}
|
||||||
syn::Item::Enum(e) => {
|
syn::Item::Enum(mut e) => {
|
||||||
if let Some(opts) = opts {
|
let opts = match opts {
|
||||||
opts.check_used()?;
|
Some(opts) => opts,
|
||||||
}
|
None => BindgenAttrs::find(&mut e.attrs)?,
|
||||||
e.macro_parse(program, (tokens,))?;
|
};
|
||||||
|
e.macro_parse(program, (tokens, opts))?;
|
||||||
}
|
}
|
||||||
syn::Item::Const(mut c) => {
|
syn::Item::Const(mut c) => {
|
||||||
let opts = match opts {
|
let opts = match opts {
|
||||||
@ -1032,15 +1038,17 @@ fn import_enum(enum_: syn::ItemEnum, program: &mut ast::Program) -> Result<(), D
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MacroParse<(&'a mut TokenStream,)> for syn::ItemEnum {
|
impl<'a> MacroParse<(&'a mut TokenStream, BindgenAttrs)> for syn::ItemEnum {
|
||||||
fn macro_parse(
|
fn macro_parse(
|
||||||
self,
|
self,
|
||||||
program: &mut ast::Program,
|
program: &mut ast::Program,
|
||||||
(tokens,): (&'a mut TokenStream,),
|
(tokens, opts): (&'a mut TokenStream, BindgenAttrs),
|
||||||
) -> Result<(), Diagnostic> {
|
) -> Result<(), Diagnostic> {
|
||||||
if self.variants.len() == 0 {
|
if self.variants.len() == 0 {
|
||||||
bail_span!(self, "cannot export empty enums to JS");
|
bail_span!(self, "cannot export empty enums to JS");
|
||||||
}
|
}
|
||||||
|
let generate_typescript = opts.skip_typescript().is_none();
|
||||||
|
opts.check_used()?;
|
||||||
|
|
||||||
// Check if the first value is a string literal
|
// Check if the first value is a string literal
|
||||||
match self.variants[0].discriminant {
|
match self.variants[0].discriminant {
|
||||||
@ -1141,8 +1149,8 @@ impl<'a> MacroParse<(&'a mut TokenStream,)> for syn::ItemEnum {
|
|||||||
variants,
|
variants,
|
||||||
comments,
|
comments,
|
||||||
hole,
|
hole,
|
||||||
|
generate_typescript,
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,6 +100,7 @@ macro_rules! shared_api {
|
|||||||
name: &'a str,
|
name: &'a str,
|
||||||
variants: Vec<EnumVariant<'a>>,
|
variants: Vec<EnumVariant<'a>>,
|
||||||
comments: Vec<&'a str>,
|
comments: Vec<&'a str>,
|
||||||
|
generate_typescript: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EnumVariant<'a> {
|
struct EnumVariant<'a> {
|
||||||
@ -110,6 +111,7 @@ macro_rules! shared_api {
|
|||||||
struct Function<'a> {
|
struct Function<'a> {
|
||||||
arg_names: Vec<String>,
|
arg_names: Vec<String>,
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
|
generate_typescript: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Struct<'a> {
|
struct Struct<'a> {
|
||||||
@ -117,12 +119,14 @@ macro_rules! shared_api {
|
|||||||
fields: Vec<StructField<'a>>,
|
fields: Vec<StructField<'a>>,
|
||||||
comments: Vec<&'a str>,
|
comments: Vec<&'a str>,
|
||||||
is_inspectable: bool,
|
is_inspectable: bool,
|
||||||
|
generate_typescript: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StructField<'a> {
|
struct StructField<'a> {
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
readonly: bool,
|
readonly: bool,
|
||||||
comments: Vec<&'a str>,
|
comments: Vec<&'a str>,
|
||||||
|
generate_typescript: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LocalModule<'a> {
|
struct LocalModule<'a> {
|
||||||
|
@ -7,6 +7,7 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
wasm-bindgen = { path = '../..' }
|
wasm-bindgen = { path = '../..' }
|
||||||
web-sys = { path = '../web-sys', features = [ 'HtmlElement', 'Node', 'Document' ] }
|
web-sys = { path = '../web-sys', features = [ 'HtmlElement', 'Node', 'Document' ] }
|
||||||
|
js-sys = { path = '../js-sys' }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ['cdylib']
|
crate-type = ['cdylib']
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
pub mod custom_section;
|
pub mod custom_section;
|
||||||
pub mod getters_setters;
|
pub mod getters_setters;
|
||||||
|
pub mod omit_definition;
|
||||||
pub mod opt_args_and_ret;
|
pub mod opt_args_and_ret;
|
||||||
pub mod optional_fields;
|
pub mod optional_fields;
|
||||||
pub mod simple_fn;
|
pub mod simple_fn;
|
||||||
|
34
crates/typescript-tests/src/omit_definition.rs
Normal file
34
crates/typescript-tests/src/omit_definition.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen(typescript_custom_section)]
|
||||||
|
const TYPE_GET_VALUE: &'static str =
|
||||||
|
"export function take_function(func: (x: number) => void): void;";
|
||||||
|
|
||||||
|
#[wasm_bindgen(skip_typescript)]
|
||||||
|
pub fn take_function(_: js_sys::Function) {}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct MyExportedStruct {
|
||||||
|
#[wasm_bindgen(skip_typescript)]
|
||||||
|
pub field: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl MyExportedStruct {
|
||||||
|
#[wasm_bindgen(skip_typescript)]
|
||||||
|
pub fn method(&mut self) {
|
||||||
|
self.field = !self.field;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(skip_typescript)]
|
||||||
|
pub fn static_func() {
|
||||||
|
panic!("oh no!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(skip_typescript)]
|
||||||
|
pub enum MyEnum {
|
||||||
|
One,
|
||||||
|
Two,
|
||||||
|
Three,
|
||||||
|
}
|
26
crates/typescript-tests/src/omit_definition.ts
Normal file
26
crates/typescript-tests/src/omit_definition.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import * as wbg from '../pkg/typescript_tests';
|
||||||
|
|
||||||
|
wbg.take_function((value) => {
|
||||||
|
// `value` should be inferred as `number` because of the
|
||||||
|
// custom typescript section. If `typescript = false` does
|
||||||
|
// not prevent the generation of a signature that takes any
|
||||||
|
// function, then this will trigger a noImplicitAny error.
|
||||||
|
console.log(value);
|
||||||
|
});
|
||||||
|
|
||||||
|
declare function assert<T>(message: T): void;
|
||||||
|
|
||||||
|
type EnableIfEnum = "MyEnum" extends keyof typeof wbg ? never : string;
|
||||||
|
assert<EnableIfEnum>("`MyEnum` type should not be exported.");
|
||||||
|
|
||||||
|
type EnableIfStruct = "MyStruct" extends keyof typeof wbg ? never : string;
|
||||||
|
assert<EnableIfStruct>("`MyStruct` type should not be exported.");
|
||||||
|
|
||||||
|
type EnableIfField = "field" extends keyof wbg.MyExportedStruct ? never : string;
|
||||||
|
assert<EnableIfField>("`field` should not exist on `MyExportedStruct`.");
|
||||||
|
|
||||||
|
type EnableIfMethod = "method" extends keyof wbg.MyExportedStruct ? never : string;
|
||||||
|
assert<EnableIfMethod>("`method` should not exist on `MyExportedStruct`.");
|
||||||
|
|
||||||
|
type EnableIfStaticMethod = "static_func" extends keyof typeof wbg.MyExportedStruct ? never : string;
|
||||||
|
assert<EnableIfStaticMethod>("`static_func` should not exist on `MyExportedStruct`.");
|
@ -0,0 +1,42 @@
|
|||||||
|
# `skip_typescript`
|
||||||
|
|
||||||
|
By default, Rust exports exposed to JavaScript will generate TypeScript definitions (unless `--no-typescript` is used). The `skip_typescript` attribute can be used to disable type generation per function, enum, struct, or field. For example:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[wasm_bindgen(skip_typescript)]
|
||||||
|
pub enum MyHiddenEnum {
|
||||||
|
One,
|
||||||
|
Two,
|
||||||
|
Three
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct MyPoint {
|
||||||
|
pub x: u32,
|
||||||
|
|
||||||
|
#[wasm_bindgen(skip_typescript)]
|
||||||
|
pub y: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl MyPoint {
|
||||||
|
|
||||||
|
#[wasm_bindgen(skip_typescript)]
|
||||||
|
pub fn stringify(&self) -> String {
|
||||||
|
format!("({}, {})", self.x, self.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Will generate the following `.d.ts` file:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
export class MyPoint {
|
||||||
|
free(): void;
|
||||||
|
x: number;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
When combined with [the `typescript_custom_section` attribute](typescript_custom_section.html), this can be used to manually specify more specific function types instead of using the generated definitions.
|
Loading…
x
Reference in New Issue
Block a user