From 62850a4bb96d06587cf2be6e375050a38b4c7cdc Mon Sep 17 00:00:00 2001 From: Alex Crichton <alex@alexcrichton.com> Date: Fri, 15 Mar 2019 08:04:25 -0700 Subject: [PATCH] Add a `raw_module` attribute to `#[wasm_bindgen]` This allows subverting the checks and resolution performed by the `module` attribute added as part of [RFC 6] and has been discussed in #1343. Closes #1343 [RFC 6]: https://github.com/rustwasm/rfcs/pull/6 --- crates/backend/src/ast.rs | 5 +++ crates/backend/src/encode.rs | 3 ++ crates/macro-support/src/parser.rs | 37 +++++++++++-------- guide/src/SUMMARY.md | 1 + .../attributes/on-js-imports/module.md | 5 +++ .../attributes/on-js-imports/raw_module.md | 19 ++++++++++ 6 files changed, 54 insertions(+), 16 deletions(-) create mode 100644 guide/src/reference/attributes/on-js-imports/raw_module.md diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index 4c317cea44fb..75c73860275c 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -79,6 +79,7 @@ pub struct Import { pub enum ImportModule { None, Named(String, Span), + RawNamed(String, Span), Inline(usize, Span), } @@ -96,6 +97,10 @@ impl Hash for ImportModule { 2u8.hash(h); idx.hash(h); } + ImportModule::RawNamed(name, _) => { + 3u8.hash(h); + name.hash(h); + } } } } diff --git a/crates/backend/src/encode.rs b/crates/backend/src/encode.rs index abc8c613762f..7a6c9df5770a 100644 --- a/crates/backend/src/encode.rs +++ b/crates/backend/src/encode.rs @@ -208,6 +208,9 @@ fn shared_import<'a>(i: &'a ast::Import, intern: &'a Interner) -> Result<Import< ast::ImportModule::Named(m, span) => { ImportModule::Named(intern.resolve_import_module(m, *span)?) } + ast::ImportModule::RawNamed(m, _span) => { + ImportModule::Named(intern.intern_str(m)) + } ast::ImportModule::Inline(idx, _) => ImportModule::Inline(*idx as u32), ast::ImportModule::None => ImportModule::None, }, diff --git a/crates/macro-support/src/parser.rs b/crates/macro-support/src/parser.rs index 574af3c27edd..d94a468070ce 100644 --- a/crates/macro-support/src/parser.rs +++ b/crates/macro-support/src/parser.rs @@ -33,6 +33,7 @@ macro_rules! attrgen { (static_method_of, StaticMethodOf(Span, Ident)), (js_namespace, JsNamespace(Span, Ident)), (module, Module(Span, String, Span)), + (raw_module, RawModule(Span, String, Span)), (inline_js, InlineJs(Span, String, Span)), (getter, Getter(Span, Option<Ident>)), (setter, Setter(Span, Option<Ident>)), @@ -1085,24 +1086,28 @@ impl MacroParse<BindgenAttrs> for syn::ItemForeignMod { )); } } - let module = match opts.module() { - Some((name, span)) => { - if opts.inline_js().is_some() { - let msg = "cannot specify both `module` and `inline_js`"; - errors.push(Diagnostic::span_error(span, msg)); - } - ast::ImportModule::Named(name.to_string(), span) + let module = if let Some((name, span)) = opts.module() { + if opts.inline_js().is_some() { + let msg = "cannot specify both `module` and `inline_js`"; + errors.push(Diagnostic::span_error(span, msg)); } - None => { - match opts.inline_js() { - Some((js, span)) => { - let i = program.inline_js.len(); - program.inline_js.push(js.to_string()); - ast::ImportModule::Inline(i, span) - } - None => ast::ImportModule::None - } + if opts.raw_module().is_some() { + let msg = "cannot specify both `module` and `raw_module`"; + errors.push(Diagnostic::span_error(span, msg)); } + ast::ImportModule::Named(name.to_string(), span) + } else if let Some((name, span)) = opts.raw_module() { + if opts.inline_js().is_some() { + let msg = "cannot specify both `raw_module` and `inline_js`"; + errors.push(Diagnostic::span_error(span, msg)); + } + ast::ImportModule::RawNamed(name.to_string(), span) + } else if let Some((js, span)) = opts.inline_js() { + let i = program.inline_js.len(); + program.inline_js.push(js.to_string()); + ast::ImportModule::Inline(i, span) + } else { + ast::ImportModule::None }; for item in self.items.into_iter() { if let Err(e) = item.macro_parse(program, module.clone()) { diff --git a/guide/src/SUMMARY.md b/guide/src/SUMMARY.md index 077c50cbe3b2..530b1286b7e2 100644 --- a/guide/src/SUMMARY.md +++ b/guide/src/SUMMARY.md @@ -66,6 +66,7 @@ - [`js_namespace`](./reference/attributes/on-js-imports/js_namespace.md) - [`method`](./reference/attributes/on-js-imports/method.md) - [`module = "blah"`](./reference/attributes/on-js-imports/module.md) + - [`raw_module = "blah"`](./reference/attributes/on-js-imports/raw_module.md) - [`static_method_of = Blah`](./reference/attributes/on-js-imports/static_method_of.md) - [`structural`](./reference/attributes/on-js-imports/structural.md) - [`variadic`](./reference/attributes/on-js-imports/variadic.md) diff --git a/guide/src/reference/attributes/on-js-imports/module.md b/guide/src/reference/attributes/on-js-imports/module.md index 4f6b4408e7c0..24643e42c731 100644 --- a/guide/src/reference/attributes/on-js-imports/module.md +++ b/guide/src/reference/attributes/on-js-imports/module.md @@ -31,3 +31,8 @@ generates JavaScript import glue like: ```js let illmatic = this.illmatic; ``` + +Note that if the string specified with `module` starts with `./`, `../`, or `/` +then it's interpreted as a path to a [local JS snippet](../../js-snippets.html). +If this doesn't work for your use case you might be interested in the +[`raw_module` attribute](raw_module.html) diff --git a/guide/src/reference/attributes/on-js-imports/raw_module.md b/guide/src/reference/attributes/on-js-imports/raw_module.md new file mode 100644 index 000000000000..1f8da2f3dfb2 --- /dev/null +++ b/guide/src/reference/attributes/on-js-imports/raw_module.md @@ -0,0 +1,19 @@ +# `raw_module = "blah"` + +This attribute performs exactly the same purpose as the [`module` +attribute](module.html) on JS imports, but it does not attempt to interpret +paths starting with `./`, `../`, or `/` as JS snippets. For example: + +```rust +#[wasm_bindgen(raw_module = "./some/js/file.js")] +extern "C" { + fn the_function(); +} +``` + +Note that if you use this attribute with a relative or absolute path, it's +likely up to the final bundler or project to assign meaning to that path. This +typically means that the JS file or module will be resolved relative to the +final location of the wasm file itself. That means that `raw_module` is likely +unsuitable for libraries on crates.io, but may be usable within end-user +applications.