Allow renaming exported functions into JS (#525)

Support the `js_name` attribute on exports as well as imports to allow exporting
types as camelCase instead of snake_case, for example.

Closes #221
This commit is contained in:
Alex Crichton 2018-07-20 12:01:28 -05:00 committed by GitHub
parent 61ef250dca
commit 9753f9150b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 103 additions and 6 deletions

View File

@ -2,6 +2,19 @@
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
## 0.2.13
Currently unreleased
### Added
* Support the `#[wasm_bindgen(js_name = foo)]` attribute on exported functions
and methods to allow renaming an export to JS. This allows JS to call it by
one name and Rust to call it by another, for example using `camelCase` in JS
and `snake_case` in Rust
--------------------------------------------------------------------------------
## 0.2.12 ## 0.2.12
Released 2018-07-19. Released 2018-07-19.

View File

@ -20,6 +20,7 @@ pub struct Export {
pub constructor: Option<String>, pub constructor: Option<String>,
pub function: Function, pub function: Function,
pub comments: Vec<String>, pub comments: Vec<String>,
pub rust_name: Ident,
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]

View File

@ -297,7 +297,7 @@ impl ToTokens for ast::Export {
0 0
}; };
let name = &self.function.name; let name = &self.rust_name;
let receiver = match self.method_self { let receiver = match self.method_self {
Some(ast::MethodSelf::ByValue) => { Some(ast::MethodSelf::ByValue) => {
let class = self.class.as_ref().unwrap(); let class = self.class.as_ref().unwrap();

View File

@ -477,10 +477,10 @@ impl ConvertToAst<BindgenAttrs> for syn::ForeignItemStatic {
} }
} }
impl ConvertToAst<()> for syn::ItemFn { impl ConvertToAst<BindgenAttrs> for syn::ItemFn {
type Target = ast::Function; type Target = ast::Function;
fn convert(self, (): ()) -> Self::Target { fn convert(self, attrs: BindgenAttrs) -> Self::Target {
match self.vis { match self.vis {
syn::Visibility::Public(_) => {} syn::Visibility::Public(_) => {}
_ => panic!("can only bindgen public functions"), _ => panic!("can only bindgen public functions"),
@ -492,7 +492,8 @@ impl ConvertToAst<()> for syn::ItemFn {
panic!("can only bindgen safe functions"); panic!("can only bindgen safe functions");
} }
function_from_decl(&self.ident, self.decl, self.attrs, self.vis, false).0 let name = attrs.js_name().unwrap_or(&self.ident);
function_from_decl(name, self.decl, self.attrs, self.vis, false).0
} }
} }
@ -584,8 +585,9 @@ impl<'a> MacroParse<(Option<BindgenAttrs>, &'a mut TokenStream)> for syn::Item {
class: None, class: None,
method_self: None, method_self: None,
constructor: None, constructor: None,
function: f.convert(()),
comments, comments,
rust_name: f.ident.clone(),
function: f.convert(opts.unwrap_or_default()),
}); });
} }
syn::Item::Struct(mut s) => { syn::Item::Struct(mut s) => {
@ -677,7 +679,7 @@ impl<'a, 'b> MacroParse<()> for (&'a Ident, &'b mut syn::ImplItem) {
}; };
let (function, method_self) = function_from_decl( let (function, method_self) = function_from_decl(
&method.sig.ident, opts.js_name().unwrap_or(&method.sig.ident),
Box::new(method.sig.decl.clone()), Box::new(method.sig.decl.clone()),
method.attrs.clone(), method.attrs.clone(),
method.vis.clone(), method.vis.clone(),
@ -690,6 +692,7 @@ impl<'a, 'b> MacroParse<()> for (&'a Ident, &'b mut syn::ImplItem) {
constructor, constructor,
function, function,
comments, comments,
rust_name: method.sig.ident.clone(),
}); });
} }
} }

View File

@ -51,3 +51,35 @@ possibilities!
const f = new Foo(); const f = new Foo();
console.log(f.get_contents()); console.log(f.get_contents());
``` ```
* `js_name` - this can be used to export a different name in JS than what
something is named in Rust, for example:
```rust
#[wasm_bindgen]
pub struct Foo {
contents: u32,
}
#[wasm_bindgen(js_name = makeFoo)]
pub fn make_foo() -> Foo {
Foo { contents: 6 }
}
#[wasm_bindgen]
impl Foo {
#[wasm_bindgen(js_name = getContents)]
pub fn get_contents(&self) -> u32 {
self.contents
}
}
```
Here this can be used in JS as:
```js
import { makeFoo } from './my_module';
const foo = makeFoo();
console.log(foo.getContents());
```

View File

@ -709,3 +709,51 @@ fn double_consume() {
"#) "#)
.test(); .test();
} }
#[test]
fn rename_function_for_js() {
project()
.file("src/lib.rs", r#"
#![feature(use_extern_macros, wasm_import_module)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub struct Foo { }
#[wasm_bindgen]
impl Foo {
#[wasm_bindgen(constructor)]
pub fn new() -> Foo {
let f = Foo {};
f.foo();
return f
}
#[wasm_bindgen(js_name = bar)]
pub fn foo(&self) {
}
}
#[wasm_bindgen(js_name = js_foo)]
pub fn foo() {}
#[wasm_bindgen]
pub fn bar() {
foo();
}
"#)
.file("test.js", r#"
import { Foo, js_foo, bar } from "./out";
export function test() {
Foo.new().bar();
js_foo();
bar();
}
"#)
.test();
}