>();
let json = serde_json::to_string_pretty(&map)?;
fs::write(out_dir.join("package.json"), json)?;
}
// And now that we've got all our JS and TypeScript, actually write it
// out to the filesystem.
let extension = if gen.mode.nodejs_experimental_modules() {
"mjs"
} else {
"js"
};
fn write(path: P, contents: C) -> Result<(), anyhow::Error>
where
P: AsRef,
C: AsRef<[u8]>,
{
fs::write(&path, contents)
.with_context(|| format!("failed to write `{}`", path.as_ref().display()))
}
let js_path = out_dir.join(&self.stem).with_extension(extension);
if gen.mode.esm_integration() {
let js_name = format!("{}_bg.{}", self.stem, extension);
let start = gen.start.as_deref().unwrap_or("");
write(
&js_path,
format!(
"import * as wasm from \"./{}.wasm\";\nexport * from \"./{}\";{}",
wasm_name, js_name, start
),
)?;
write(&out_dir.join(&js_name), reset_indentation(&gen.js))?;
} else {
write(&js_path, reset_indentation(&gen.js))?;
}
if gen.typescript {
let ts_path = js_path.with_extension("d.ts");
fs::write(&ts_path, &gen.ts)
.with_context(|| format!("failed to write `{}`", ts_path.display()))?;
}
if gen.typescript {
let ts_path = wasm_path.with_extension("d.ts");
let ts = wasm2es6js::typescript(&self.module)?;
fs::write(&ts_path, ts)
.with_context(|| format!("failed to write `{}`", ts_path.display()))?;
}
Ok(())
}
}
fn gc_module_and_adapters(module: &mut Module) {
loop {
// Fist up, cleanup the native wasm module. Note that roots can come
// from custom sections, namely our wasm interface types custom section
// as well as the aux section.
walrus::passes::gc::run(module);
// ... and afterwards we can delete any `implements` directives for any
// imports that have been deleted.
let imports_remaining = module
.imports
.iter()
.map(|i| i.id())
.collect::>();
let mut section = module
.customs
.delete_typed::()
.unwrap();
section
.implements
.retain(|pair| imports_remaining.contains(&pair.0));
// ... and after we delete the `implements` directive we try to
// delete some adapters themselves. If nothing is deleted, then we're
// good to go. If something is deleted though then we may have free'd up
// some functions in the main module to get deleted, so go again to gc
// things.
let aux = module.customs.get_typed::().unwrap();
let any_removed = section.gc(aux);
module.customs.add(*section);
if !any_removed {
break;
}
}
}
/// Returns a sorted iterator over a hash map, sorted based on key.
///
/// The intention of this API is to be used whenever the iteration order of a
/// `HashMap` might affect the generated JS bindings. We want to ensure that the
/// generated output is deterministic and we do so by ensuring that iteration of
/// hash maps is consistently sorted.
fn sorted_iter(map: &HashMap) -> impl Iterator-
where
K: Ord,
{
let mut pairs = map.iter().collect::>();
pairs.sort_by_key(|(k, _)| *k);
pairs.into_iter()
}