diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index 265f4ac6..375af0a2 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -116,7 +116,7 @@ pub struct ImportStatic { pub ty: syn::Type, pub shim: Ident, pub rust_name: Ident, - pub js_name: Ident, + pub js_name: String, } #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] @@ -143,7 +143,7 @@ pub struct ImportEnum { #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] pub struct Function { - pub name: Ident, + pub name: String, pub arguments: Vec, pub ret: Option, pub rust_attrs: Vec, diff --git a/crates/macro-support/src/parser.rs b/crates/macro-support/src/parser.rs index 2e935843..3752251d 100644 --- a/crates/macro-support/src/parser.rs +++ b/crates/macro-support/src/parser.rs @@ -149,11 +149,11 @@ impl BindgenAttrs { } /// Get the first js_name attribute - fn js_name(&self) -> Option<&Ident> { + fn js_name(&self) -> Option<&str> { self.attrs .iter() .filter_map(|a| match a { - BindgenAttr::JsName(s) => Some(s), + BindgenAttr::JsName(s) => Some(&s[..]), _ => None, }) .next() @@ -200,7 +200,7 @@ pub enum BindgenAttr { Setter(Option), Structural, Readonly, - JsName(Ident), + JsName(String), JsClass(String), } @@ -267,8 +267,12 @@ impl syn::synom::Synom for BindgenAttr { do_parse!( call!(term, "js_name") >> punct!(=) >> - ns: call!(term2ident) >> - (ns) + name: alt!( + syn!(syn::LitStr) => { |s| s.value() } + | + call!(term2ident) => { |s| s.to_string() } + ) >> + (name) )=> { BindgenAttr::JsName } | do_parse!( @@ -365,9 +369,10 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option)> for syn::ForeignItemFn fn convert(self, (opts, module): (BindgenAttrs, &'a Option)) -> Result { - let js_name = opts.js_name().unwrap_or(&self.ident).clone(); + let default_name = self.ident.to_string(); + let js_name = opts.js_name().unwrap_or(&default_name); let wasm = function_from_decl( - &js_name, + js_name, self.decl.clone(), self.attrs.clone(), self.vis.clone(), @@ -475,7 +480,9 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option)> for syn::ForeignItemFn ast::ImportFunctionKind::Method { ref class, .. } => (1, &class[..]), }; let data = (ns, &self.ident, module); - format!("__wbg_{}_{}", js_name, ShortHash(data)) + format!("__wbg_{}_{}", + js_name.chars().filter(|c| c.is_ascii_alphanumeric()).collect::(), + ShortHash(data)) }; Ok(ast::ImportKind::Function(ast::ImportFunction { function: wasm, @@ -510,13 +517,16 @@ impl ConvertToAst for syn::ForeignItemStatic { if self.mutability.is_some() { bail_span!(self.mutability, "cannot import mutable globals yet") } - let js_name = opts.js_name().unwrap_or(&self.ident); - let shim = format!("__wbg_static_accessor_{}_{}", js_name, self.ident); + let default_name = self.ident.to_string(); + let js_name = opts.js_name().unwrap_or(&default_name); + let shim = format!("__wbg_static_accessor_{}_{}", + js_name.chars().filter(|c| c.is_ascii_alphanumeric()).collect::(), + self.ident); Ok(ast::ImportKind::Static(ast::ImportStatic { ty: *self.ty, vis: self.vis, rust_name: self.ident.clone(), - js_name: js_name.clone(), + js_name: js_name.to_string(), shim: Ident::new(&shim, Span::call_site()), })) } @@ -537,14 +547,15 @@ impl ConvertToAst for syn::ItemFn { bail_span!(self.unsafety, "can only #[wasm_bindgen] safe functions"); } - let name = attrs.js_name().unwrap_or(&self.ident); + let default_name = self.ident.to_string(); + let name = attrs.js_name().unwrap_or(&default_name); Ok(function_from_decl(name, self.decl, self.attrs, self.vis, false, None)?.0) } } /// Construct a function (and gets the self type if appropriate) for our AST from a syn function. fn function_from_decl( - name: &Ident, + name: &str, decl: Box, attrs: Vec, vis: syn::Visibility, @@ -619,7 +630,7 @@ fn function_from_decl( Ok(( ast::Function { - name: name.clone(), + name: name.to_string(), arguments, ret, rust_vis: vis, @@ -782,7 +793,7 @@ impl<'a, 'b> MacroParse<()> for (&'a Ident, &'b mut syn::ImplItem) { }; let (function, method_self) = function_from_decl( - opts.js_name().unwrap_or(&method.sig.ident), + opts.js_name().unwrap_or(&method.sig.ident.to_string()), Box::new(method.sig.decl.clone()), method.attrs.clone(), method.vis.clone(), diff --git a/crates/webidl/src/util.rs b/crates/webidl/src/util.rs index 507a32b9..26c1e5fc 100644 --- a/crates/webidl/src/util.rs +++ b/crates/webidl/src/util.rs @@ -563,7 +563,7 @@ impl<'a> FirstPassRecord<'a> { name.to_snake_case() } ); - let name = raw_ident(name); + let name = name.to_string(); let arguments = self.webidl_arguments_to_syn_arg_captured(arguments.into_iter(), &kind)?; diff --git a/tests/all/imports.rs b/tests/all/imports.rs index 0a7add00..4b6c6201 100644 --- a/tests/all/imports.rs +++ b/tests/all/imports.rs @@ -36,6 +36,91 @@ fn unused_imports_not_generated() { assert!(!contents.contains("foo"), "found `foo` in {}", contents); } +#[test] +fn rename_with_string() { + project() + .file( + "src/lib.rs", + r#" + #![feature(use_extern_macros)] + + extern crate wasm_bindgen; + + use wasm_bindgen::prelude::*; + + #[wasm_bindgen(module = "./test")] + extern { + #[wasm_bindgen(js_name = "baz$")] + fn foo(); + } + + #[wasm_bindgen] + pub fn run() { + foo(); + } + "#, + ) + .file( + "test.js", + r#" + import * as wasm from "./out"; + import * as assert from "assert"; + + let called = false; + + export function baz$() { + called = true; + } + + export function test() { + wasm.run(); + assert.strictEqual(called, true); + } + "#, + ) + .test(); +} + +#[test] +fn rename_static_with_string() { + project() + .debug(false) + .file( + "src/lib.rs", + r#" + #![feature(use_extern_macros)] + + extern crate wasm_bindgen; + + use wasm_bindgen::prelude::*; + + #[wasm_bindgen(module = "./test")] + extern { + #[wasm_bindgen(js_name = "$foo")] + static FOO: JsValue; + } + + #[wasm_bindgen] + pub fn run() { + assert_eq!(FOO.as_f64(), Some(1.0)); + } + "#, + ) + .file( + "test.js", + r#" + import { run } from "./out"; + + export const $foo = 1.0; + + export function test() { + run(); + } + "#, + ) + .test(); +} + #[test] fn versions() { project()