Skip to content

Commit

Permalink
Generate a *.d.ts file for wasm files
Browse files Browse the repository at this point in the history
This generates a `*.d.ts` file for the wasm file that wasm-bindgen emits
whenever typescript is enable *in addition* to the `*.d.ts` file that
already exists for the JS shim.

Closes rustwasm#1040
  • Loading branch information
alexcrichton committed Nov 27, 2018
1 parent 4a70198 commit 047c41c
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 71 deletions.
10 changes: 9 additions & 1 deletion crates/cli-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ impl Bindgen {
.with_context(|_| format!("failed to write `{}`", js_path.display()))?;

if self.typescript {
let ts_path = out_dir.join(stem).with_extension("d.ts");
let ts_path = js_path.with_extension("d.ts");
fs::write(&ts_path, ts)
.with_context(|_| format!("failed to write `{}`", ts_path.display()))?;
}
Expand All @@ -230,9 +230,17 @@ impl Bindgen {
.with_context(|_| format!("failed to write `{}`", js_path.display()))?;
}

if self.typescript {
let ts_path = wasm_path.with_extension("d.ts");
let ts = wasm2es6js::typescript(&module);
fs::write(&ts_path, ts)
.with_context(|_| format!("failed to write `{}`", ts_path.display()))?;
}

let wasm_bytes = parity_wasm::serialize(module)?;
fs::write(&wasm_path, wasm_bytes)
.with_context(|_| format!("failed to write `{}`", wasm_path.display()))?;

Ok(())
}

Expand Down
135 changes: 65 additions & 70 deletions crates/cli-support/src/wasm2es6js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,82 +48,77 @@ impl Config {
}
}

impl Output {
pub fn typescript(&self) -> String {
let mut exports = format!("/* tslint:disable */\n");

if let Some(i) = self.module.export_section() {
let imported_functions = self
.module
.import_section()
.map(|m| m.functions() as u32)
.unwrap_or(0);
for entry in i.entries() {
let idx = match *entry.internal() {
Internal::Function(i) => i - imported_functions,
Internal::Memory(_) => {
exports.push_str(&format!(
"
export const {}: WebAssembly.Memory;
",
entry.field()
));
continue;
}
Internal::Table(_) => {
exports.push_str(&format!(
"
export const {}: WebAssembly.Table;
",
entry.field()
));
continue;
}
Internal::Global(_) => continue,
};

let functions = self
.module
.function_section()
.expect("failed to find function section");
let idx = functions.entries()[idx as usize].type_ref();

let types = self
.module
.type_section()
.expect("failed to find type section");
let ty = match types.types()[idx as usize] {
Type::Function(ref f) => f,
};
let mut args = String::new();
for (i, _) in ty.params().iter().enumerate() {
if i > 0 {
args.push_str(", ");
}
args.push((b'a' + (i as u8)) as char);
args.push_str(": number");
pub fn typescript(module: &Module) -> String {
let mut exports = format!("/* tslint:disable */\n");

if let Some(i) = module.export_section() {
let imported_functions = module
.import_section()
.map(|m| m.functions() as u32)
.unwrap_or(0);
for entry in i.entries() {
let idx = match *entry.internal() {
Internal::Function(i) => i - imported_functions,
Internal::Memory(_) => {
exports.push_str(&format!(
"export const {}: WebAssembly.Memory;\n",
entry.field()
));
continue;
}

exports.push_str(&format!(
"
export function {name}({args}): {ret};
",
name = entry.field(),
args = args,
ret = if ty.return_type().is_some() {
"number"
} else {
"void"
},
));
Internal::Table(_) => {
exports.push_str(&format!(
"export const {}: WebAssembly.Table;\n",
entry.field()
));
continue;
}
Internal::Global(_) => continue,
};

let functions = module
.function_section()
.expect("failed to find function section");
let idx = functions.entries()[idx as usize].type_ref();

let types = module
.type_section()
.expect("failed to find type section");
let ty = match types.types()[idx as usize] {
Type::Function(ref f) => f,
};
let mut args = String::new();
for (i, _) in ty.params().iter().enumerate() {
if i > 0 {
args.push_str(", ");
}
args.push((b'a' + (i as u8)) as char);
args.push_str(": number");
}

exports.push_str(&format!(
"export function {name}({args}): {ret};\n",
name = entry.field(),
args = args,
ret = if ty.return_type().is_some() {
"number"
} else {
"void"
},
));
}
}

return exports;
}

impl Output {
pub fn typescript(&self) -> String {
let mut ts = typescript(&self.module);
if self.base64 {
exports.push_str("export const booted: Promise<boolean>;");
ts.push_str("export const booted: Promise<boolean>;\n");
}

return exports;
return ts
}

pub fn js(self) -> Result<String, Error> {
Expand Down

0 comments on commit 047c41c

Please sign in to comment.