#![doc(html_root_url = "https://docs.rs/wasm-bindgen-cli-support/0.2")]
use failure::{bail, Error, ResultExt};
use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::env;
use std::fs;
use std::mem;
use std::path::{Path, PathBuf};
use std::str;
use walrus::Module;
use wasm_bindgen_wasm_conventions as wasm_conventions;
mod anyref;
mod decode;
mod descriptor;
mod descriptors;
mod intrinsic;
mod js;
pub mod wasm2es6js;
mod webidl;
pub struct Bindgen {
input: Input,
out_name: Option,
mode: OutputMode,
debug: bool,
typescript: bool,
demangle: bool,
keep_debug: bool,
remove_name_section: bool,
remove_producers_section: bool,
emit_start: bool,
// Experimental support for weakrefs, an upcoming ECMAScript feature.
// Currently only enable-able through an env var.
weak_refs: bool,
// Support for the wasm threads proposal, transforms the wasm module to be
// "ready to be instantiated on any thread"
threads: wasm_bindgen_threads_xform::Config,
anyref: bool,
multi_value: bool,
wasm_interface_types: bool,
encode_into: EncodeInto,
}
pub struct Output {
module: walrus::Module,
stem: String,
js: String,
ts: String,
mode: OutputMode,
typescript: bool,
snippets: HashMap>,
local_modules: HashMap,
npm_dependencies: HashMap,
wasm_interface_types: bool,
}
#[derive(Clone)]
enum OutputMode {
Bundler { browser_only: bool },
Web,
NoModules { global: String },
Node { experimental_modules: bool },
}
enum Input {
Path(PathBuf),
Module(Module, String),
None,
}
pub enum EncodeInto {
Test,
Always,
Never,
}
impl Bindgen {
pub fn new() -> Bindgen {
let anyref = env::var("WASM_BINDGEN_ANYREF").is_ok();
let wasm_interface_types = env::var("WASM_INTERFACE_TYPES").is_ok();
let multi_value = env::var("WASM_BINDGEN_MULTI_VALUE").is_ok();
Bindgen {
input: Input::None,
out_name: None,
mode: OutputMode::Bundler {
browser_only: false,
},
debug: false,
typescript: false,
demangle: true,
keep_debug: false,
remove_name_section: false,
remove_producers_section: false,
emit_start: true,
weak_refs: env::var("WASM_BINDGEN_WEAKREF").is_ok(),
threads: threads_config(),
anyref: anyref || wasm_interface_types,
multi_value,
wasm_interface_types,
encode_into: EncodeInto::Test,
}
}
pub fn input_path>(&mut self, path: P) -> &mut Bindgen {
self.input = Input::Path(path.as_ref().to_path_buf());
self
}
pub fn out_name(&mut self, name: &str) -> &mut Bindgen {
self.out_name = Some(name.to_string());
self
}
/// Explicitly specify the already parsed input module.
pub fn input_module(&mut self, name: &str, module: Module) -> &mut Bindgen {
let name = name.to_string();
self.input = Input::Module(module, name);
return self;
}
fn switch_mode(&mut self, mode: OutputMode, flag: &str) -> Result<(), Error> {
match self.mode {
OutputMode::Bundler { .. } => self.mode = mode,
_ => bail!(
"cannot specify `{}` with another output mode already specified",
flag
),
}
Ok(())
}
pub fn nodejs(&mut self, node: bool) -> Result<&mut Bindgen, Error> {
if node {
self.switch_mode(
OutputMode::Node {
experimental_modules: false,
},
"--target nodejs",
)?;
}
Ok(self)
}
pub fn nodejs_experimental_modules(&mut self, node: bool) -> Result<&mut Bindgen, Error> {
if node {
self.switch_mode(
OutputMode::Node {
experimental_modules: true,
},
"--nodejs-experimental-modules",
)?;
}
Ok(self)
}
pub fn bundler(&mut self, bundler: bool) -> Result<&mut Bindgen, Error> {
if bundler {
self.switch_mode(
OutputMode::Bundler {
browser_only: false,
},
"--target bundler",
)?;
}
Ok(self)
}
pub fn web(&mut self, web: bool) -> Result<&mut Bindgen, Error> {
if web {
self.switch_mode(OutputMode::Web, "--target web")?;
}
Ok(self)
}
pub fn no_modules(&mut self, no_modules: bool) -> Result<&mut Bindgen, Error> {
if no_modules {
self.switch_mode(
OutputMode::NoModules {
global: "wasm_bindgen".to_string(),
},
"--target no-modules",
)?;
}
Ok(self)
}
pub fn browser(&mut self, browser: bool) -> Result<&mut Bindgen, Error> {
if browser {
match &mut self.mode {
OutputMode::Bundler { browser_only } => *browser_only = true,
_ => bail!("cannot specify `--browser` with other output types"),
}
}
Ok(self)
}
pub fn no_modules_global(&mut self, name: &str) -> Result<&mut Bindgen, Error> {
match &mut self.mode {
OutputMode::NoModules { global } => *global = name.to_string(),
_ => bail!("can only specify `--no-modules-global` with `--target no-modules`"),
}
Ok(self)
}
pub fn debug(&mut self, debug: bool) -> &mut Bindgen {
self.debug = debug;
self
}
pub fn typescript(&mut self, typescript: bool) -> &mut Bindgen {
self.typescript = typescript;
self
}
pub fn demangle(&mut self, demangle: bool) -> &mut Bindgen {
self.demangle = demangle;
self
}
pub fn keep_debug(&mut self, keep_debug: bool) -> &mut Bindgen {
self.keep_debug = keep_debug;
self
}
pub fn remove_name_section(&mut self, remove: bool) -> &mut Bindgen {
self.remove_name_section = remove;
self
}
pub fn remove_producers_section(&mut self, remove: bool) -> &mut Bindgen {
self.remove_producers_section = remove;
self
}
pub fn emit_start(&mut self, emit: bool) -> &mut Bindgen {
self.emit_start = emit;
self
}
pub fn encode_into(&mut self, mode: EncodeInto) -> &mut Bindgen {
self.encode_into = mode;
self
}
pub fn generate>(&mut self, path: P) -> Result<(), Error> {
self.generate_output()?.emit(path.as_ref())
}
pub fn generate_output(&mut self) -> Result