Implement the local JS snippets RFC

This commit is an implementation of [RFC 6] which enables crates to
inline local JS snippets into the final output artifact of
`wasm-bindgen`. This is accompanied with a few minor breaking changes
which are intended to be relatively minor in practice:

* The `module` attribute disallows paths starting with `./` and `../`.
  It requires paths starting with `/` to actually exist on the filesystem.
* The `--browser` flag no longer emits bundler-compatible code, but
  rather emits an ES module that can be natively loaded into a browser.

Otherwise be sure to check out [the RFC][RFC 6] for more details, and
otherwise this should implement at least the MVP version of the RFC!
Notably at this time JS snippets with `--nodejs` or `--no-modules` are
not supported and will unconditionally generate an error.

[RFC 6]: https://github.com/rustwasm/rfcs/pull/6

Closes #1311
This commit is contained in:
Alex Crichton
2019-02-25 11:11:30 -08:00
parent f161717afe
commit b762948456
32 changed files with 985 additions and 380 deletions

View File

@ -9,6 +9,7 @@ documentation = "https://docs.rs/wasm-bindgen"
description = """
The part of the implementation of the `#[wasm_bindgen]` attribute that is not in the shared backend crate
"""
edition = '2018'
[features]
spans = ["wasm-bindgen-backend/spans"]

View File

@ -12,8 +12,8 @@ extern crate wasm_bindgen_backend as backend;
extern crate wasm_bindgen_shared as shared;
use backend::{Diagnostic, TryToTokens};
pub use parser::BindgenAttrs;
use parser::MacroParse;
pub use crate::parser::BindgenAttrs;
use crate::parser::MacroParse;
use proc_macro2::TokenStream;
use quote::ToTokens;
use quote::TokenStreamExt;

View File

@ -33,6 +33,7 @@ macro_rules! attrgen {
(static_method_of, StaticMethodOf(Span, Ident)),
(js_namespace, JsNamespace(Span, Ident)),
(module, Module(Span, String, Span)),
(inline_js, InlineJs(Span, String, Span)),
(getter, Getter(Span, Option<Ident>)),
(setter, Setter(Span, Option<Ident>)),
(indexing_getter, IndexingGetter(Span)),
@ -339,12 +340,12 @@ impl<'a> ConvertToAst<BindgenAttrs> for &'a mut syn::ItemStruct {
}
}
impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn {
impl<'a> ConvertToAst<(BindgenAttrs, &'a ast::ImportModule)> for syn::ForeignItemFn {
type Target = ast::ImportKind;
fn convert(
self,
(opts, module): (BindgenAttrs, &'a Option<String>),
(opts, module): (BindgenAttrs, &'a ast::ImportModule),
) -> Result<Self::Target, Diagnostic> {
let wasm = function_from_decl(
&self.ident,
@ -543,12 +544,12 @@ impl ConvertToAst<BindgenAttrs> for syn::ForeignItemType {
}
}
impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemStatic {
impl<'a> ConvertToAst<(BindgenAttrs, &'a ast::ImportModule)> for syn::ForeignItemStatic {
type Target = ast::ImportKind;
fn convert(
self,
(opts, module): (BindgenAttrs, &'a Option<String>),
(opts, module): (BindgenAttrs, &'a ast::ImportModule),
) -> Result<Self::Target, Diagnostic> {
if self.mutability.is_some() {
bail_span!(self.mutability, "cannot import mutable globals yet")
@ -1084,8 +1085,27 @@ impl MacroParse<BindgenAttrs> for syn::ItemForeignMod {
));
}
}
for mut item in self.items.into_iter() {
if let Err(e) = item.macro_parse(program, &opts) {
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)
}
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
}
}
};
for item in self.items.into_iter() {
if let Err(e) = item.macro_parse(program, module.clone()) {
errors.push(e);
}
}
@ -1095,11 +1115,11 @@ impl MacroParse<BindgenAttrs> for syn::ItemForeignMod {
}
}
impl<'a> MacroParse<&'a BindgenAttrs> for syn::ForeignItem {
impl MacroParse<ast::ImportModule> for syn::ForeignItem {
fn macro_parse(
mut self,
program: &mut ast::Program,
opts: &'a BindgenAttrs,
module: ast::ImportModule,
) -> Result<(), Diagnostic> {
let item_opts = {
let attrs = match self {
@ -1110,11 +1130,7 @@ impl<'a> MacroParse<&'a BindgenAttrs> for syn::ForeignItem {
};
BindgenAttrs::find(attrs)?
};
let module = item_opts
.module()
.or(opts.module())
.map(|s| s.0.to_string());
let js_namespace = item_opts.js_namespace().or(opts.js_namespace()).cloned();
let js_namespace = item_opts.js_namespace().cloned();
let kind = match self {
syn::ForeignItem::Fn(f) => f.convert((item_opts, &module))?,
syn::ForeignItem::Type(t) => t.convert(item_opts)?,