Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds support for #[wasm_bindgen(typescript_custom_section)]. #1048

Merged
merged 1 commit into from
Nov 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/backend/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub struct Program {
/// objects" in the sense that they represent a JS object with a particular
/// shape in JIT parlance.
pub dictionaries: Vec<Dictionary>,
/// custom typescript sections to be included in the definition file
pub typescript_custom_sections: Vec<String>,
}

/// A rust to js interface. Allows interaction with rust objects/functions
Expand Down
1 change: 1 addition & 0 deletions crates/backend/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ fn shared_program<'a>(prog: &'a ast::Program, intern: &'a Interner)
imports: prog.imports.iter()
.map(|a| shared_import(a, intern))
.collect::<Result<Vec<_>, _>>()?,
typescript_custom_sections: prog.typescript_custom_sections.iter().map(|x| -> &'a str { &x }).collect(),
// version: shared::version(),
// schema_version: shared::SCHEMA_VERSION.to_string(),
})
Expand Down
4 changes: 4 additions & 0 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2143,6 +2143,10 @@ impl<'a, 'b> SubContext<'a, 'b> {
for s in self.program.structs.iter() {
self.generate_struct(s)?;
}
for s in self.program.typescript_custom_sections.iter() {
self.cx.typescript.push_str(s);
self.cx.typescript.push_str("\n\n");
}

Ok(())
}
Expand Down
53 changes: 48 additions & 5 deletions crates/macro-support/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,13 @@ impl BindgenAttrs {
_ => false,
})
}

fn typescript_custom_section(&self) -> bool {
self.attrs.iter().any(|a| match *a {
BindgenAttr::TypescriptCustomSection => true,
_ => false,
})
}
}

impl Parse for BindgenAttrs {
Expand Down Expand Up @@ -244,6 +251,7 @@ pub enum BindgenAttr {
Extends(syn::Path),
VendorPrefix(Ident),
Variadic,
TypescriptCustomSection,
}

impl Parse for BindgenAttr {
Expand Down Expand Up @@ -334,6 +342,9 @@ impl Parse for BindgenAttr {
};
return Ok(BindgenAttr::JsName(val, span));
}
if attr == "typescript_custom_section" {
return Ok(BindgenAttr::TypescriptCustomSection);
}

Err(original.error("unknown attribute"))
}
Expand Down Expand Up @@ -810,11 +821,20 @@ impl<'a> MacroParse<(Option<BindgenAttrs>, &'a mut TokenStream)> for syn::Item {
e.to_tokens(tokens);
e.macro_parse(program, ())?;
}
_ => bail_span!(
self,
"#[wasm_bindgen] can only be applied to a function, \
struct, enum, impl, or extern block"
),
syn::Item::Const(mut c) => {
let opts = match opts {
Some(opts) => opts,
None => BindgenAttrs::find(&mut c.attrs)?,
};
c.macro_parse(program, opts)?;
}
_ => {
bail_span!(
self,
"#[wasm_bindgen] can only be applied to a function, \
struct, enum, impl, or extern block",
);
}
}

Ok(())
Expand Down Expand Up @@ -992,6 +1012,29 @@ impl MacroParse<()> for syn::ItemEnum {
}
}

impl MacroParse<BindgenAttrs> for syn::ItemConst {
fn macro_parse(self, program: &mut ast::Program, opts: BindgenAttrs) -> Result<(), Diagnostic> {
// Shortcut
if !opts.typescript_custom_section() {
bail_span!(self, "#[wasm_bindgen] will not work on constants unless you are defining a #[wasm_bindgen(typescript_custom_section)].");
}

match *self.expr {
syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(litstr),
..
}) => {
program.typescript_custom_sections.push(litstr.value());
},
_ => {
bail_span!(self, "Expected a string literal to be used with #[wasm_bindgen(typescript_custom_section)].");
},
}

Ok(())
}
}

impl MacroParse<BindgenAttrs> for syn::ItemForeignMod {
fn macro_parse(self, program: &mut ast::Program, opts: BindgenAttrs) -> Result<(), Diagnostic> {
let mut errors = Vec::new();
Expand Down
1 change: 1 addition & 0 deletions crates/shared/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ struct Program<'a> {
enums: Vec<Enum<'a>>,
imports: Vec<Import<'a>>,
structs: Vec<Struct<'a>>,
typescript_custom_sections: Vec<&'a str>,
// version: &'a str,
// schema_version: &'a str,
}
Expand Down
1 change: 1 addition & 0 deletions guide/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
- [`constructor`](./reference/attributes/on-rust-exports/constructor.md)
- [`js_name = Blah`](./reference/attributes/on-rust-exports/js_name.md)
- [`readonly`](./reference/attributes/on-rust-exports/readonly.md)
- [`typescript_custom_section`](./reference/attributes/on-rust-exports/typescript_custom_section.md)

--------------------------------------------------------------------------------

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# `typescript_custom_section`

When added to a `const` `&'static str`, it will append the contents of the
string to the `.d.ts` file exported by `wasm-bindgen-cli` (when the
`--typescript` flag is enabled).

```rust
#[wasm_bindgen(typescript_custom_section)]
const TS_APPEND_CONTENT: &'static str = r#"

export type Coords = { "latitude": number, "longitude": number, };

"#;
```

The primary target for this feature is for code generation. For example, you
can author a macro that allows you to export a TypeScript definition alongside
the definition of a struct or Rust type.

```rust
#[derive(MyTypescriptExport)]
struct Coords {
latitude: u32,
longitude: u32,
}
```

The proc_derive_macro "MyTypescriptExport" can export its own
`#[wasm_bindgen(typescript_custom_section)]` section, which would then be
picked up by wasm-bindgen-cli. This would be equivalent to the contents of
the TS_APPEND_CONTENT string in the first example.

This feature allows plain data objects to be typechecked in Rust and in
TypeScript by outputing a type definition generated at compile time.