From 70085b0f884b8fc5540003b27d116ec1ea09af04 Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Sat, 9 Nov 2024 22:26:55 +0100 Subject: [PATCH 1/3] Add `export_type` attribute to export string enums --- crates/backend/src/ast.rs | 3 + crates/backend/src/encode.rs | 1 + crates/cli-support/src/js/mod.rs | 10 ++- crates/cli-support/src/wit/mod.rs | 1 + crates/cli-support/src/wit/nonstandard.rs | 2 + crates/cli/tests/reference/enums.d.ts | 4 + crates/cli/tests/reference/enums.rs | 7 ++ crates/macro-support/src/parser.rs | 20 ++++- crates/shared/src/lib.rs | 1 + guide/src/SUMMARY.md | 1 + .../attributes/on-rust-exports/export_type.md | 84 +++++++++++++++++++ .../attributes/on-rust-exports/index.md | 3 +- 12 files changed, 129 insertions(+), 8 deletions(-) create mode 100644 guide/src/reference/attributes/on-rust-exports/export_type.md diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index d745f325f9e..f2ba0db672e 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -349,6 +349,9 @@ pub struct StringEnum { pub rust_attrs: Vec, /// Whether to generate a typescript definition for this enum pub generate_typescript: bool, + /// Whether the type generated for this string enum should be publicly + /// exported as part of the API of the generated JS module + pub export_type: bool, /// Path to wasm_bindgen pub wasm_bindgen: Path, } diff --git a/crates/backend/src/encode.rs b/crates/backend/src/encode.rs index bc82ba5c336..9e001540778 100644 --- a/crates/backend/src/encode.rs +++ b/crates/backend/src/encode.rs @@ -363,6 +363,7 @@ fn shared_import_enum<'a>(i: &'a ast::StringEnum, _intern: &'a Interner) -> Stri StringEnum { name: &i.js_name, generate_typescript: i.generate_typescript, + export_type: i.export_type, variant_values: i.variant_values.iter().map(|x| &**x).collect(), comments: i.comments.iter().map(|s| &**s).collect(), } diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index aff91c6cfcc..13a91a6e6a1 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -3972,9 +3972,10 @@ __wbg_set_wasm(wasm);" .collect(); if string_enum.generate_typescript - && self - .typescript_refs - .contains(&TsReference::StringEnum(string_enum.name.clone())) + && (string_enum.export_type + || self + .typescript_refs + .contains(&TsReference::StringEnum(string_enum.name.clone()))) { let docs = format_doc_comments(&string_enum.comments, None); let type_expr = if variants.is_empty() { @@ -3984,6 +3985,9 @@ __wbg_set_wasm(wasm);" }; self.typescript.push_str(&docs); + if string_enum.export_type { + self.typescript.push_str("export "); + } self.typescript.push_str("type "); self.typescript.push_str(&string_enum.name); self.typescript.push_str(" = "); diff --git a/crates/cli-support/src/wit/mod.rs b/crates/cli-support/src/wit/mod.rs index 3e3e355c366..6f7bace688f 100644 --- a/crates/cli-support/src/wit/mod.rs +++ b/crates/cli-support/src/wit/mod.rs @@ -877,6 +877,7 @@ impl<'a> Context<'a> { .map(|v| v.to_string()) .collect(), generate_typescript: string_enum.generate_typescript, + export_type: string_enum.export_type, }; let mut result = Ok(()); self.aux diff --git a/crates/cli-support/src/wit/nonstandard.rs b/crates/cli-support/src/wit/nonstandard.rs index ac0f6d6eb6b..38e392006da 100644 --- a/crates/cli-support/src/wit/nonstandard.rs +++ b/crates/cli-support/src/wit/nonstandard.rs @@ -185,6 +185,8 @@ pub struct AuxStringEnum { pub variant_values: Vec, /// Whether typescript bindings should be generated for this enum. pub generate_typescript: bool, + /// Whether typescript bindings should be exported. + pub export_type: bool, } #[derive(Debug)] diff --git a/crates/cli/tests/reference/enums.d.ts b/crates/cli/tests/reference/enums.d.ts index 1c830d483f9..20f79519003 100644 --- a/crates/cli/tests/reference/enums.d.ts +++ b/crates/cli/tests/reference/enums.d.ts @@ -31,3 +31,7 @@ export enum ImplicitDiscriminant { * The name of a color. */ type ColorName = "green" | "yellow" | "red"; +/** + * An unused string enum that has its typed exported. + */ +export type FooBarBaz = "foo" | "bar"; diff --git a/crates/cli/tests/reference/enums.rs b/crates/cli/tests/reference/enums.rs index 480dba7ce89..977a486755d 100644 --- a/crates/cli/tests/reference/enums.rs +++ b/crates/cli/tests/reference/enums.rs @@ -52,6 +52,13 @@ pub enum UnusedStringEnum { Bar = "bar", } +/// An unused string enum that has its typed exported. +#[wasm_bindgen(js_name = "FooBarBaz", export_type)] +pub enum ExportedUnusedStringEnum { + Foo = "foo", + Bar = "bar", +} + #[wasm_bindgen] enum PrivateStringEnum { Foo = "foo", diff --git a/crates/macro-support/src/parser.rs b/crates/macro-support/src/parser.rs index a2be7045d05..0dd5e66fd1c 100644 --- a/crates/macro-support/src/parser.rs +++ b/crates/macro-support/src/parser.rs @@ -95,6 +95,7 @@ macro_rules! attrgen { (typescript_type, TypeScriptType(Span, String, Span)), (getter_with_clone, GetterWithClone(Span)), (static_string, StaticString(Span)), + (export_type, ExportType(Span)), (thread_local, ThreadLocal(Span)), // For testing purposes only. @@ -1341,6 +1342,7 @@ fn string_enum( program: &mut ast::Program, js_name: String, generate_typescript: bool, + export_type: bool, comments: Vec, ) -> Result<(), Diagnostic> { let mut variants = vec![]; @@ -1380,6 +1382,7 @@ fn string_enum( comments, rust_attrs: enum_.attrs, generate_typescript, + export_type, wasm_bindgen: program.wasm_bindgen.clone(), }), }); @@ -1413,8 +1416,6 @@ impl<'a> MacroParse<(&'a mut TokenStream, BindgenAttrs)> for syn::ItemEnum { .map_or_else(|| self.ident.to_string(), |s| s.to_string()); let comments = extract_doc_comments(&self.attrs); - opts.check_used(); - // Check if the enum is a string enum, by checking whether any variant has a string discriminant. let is_string_enum = self.variants.iter().any(|v| { if let Some((_, expr)) = &v.discriminant { @@ -1429,9 +1430,22 @@ impl<'a> MacroParse<(&'a mut TokenStream, BindgenAttrs)> for syn::ItemEnum { false }); if is_string_enum { - return string_enum(self, program, js_name, generate_typescript, comments); + let export_ype = opts.export_type().is_some(); + + opts.check_used(); + + return string_enum( + self, + program, + js_name, + generate_typescript, + export_ype, + comments, + ); } + opts.check_used(); + match self.vis { syn::Visibility::Public(_) => {} _ => bail_span!(self, "only public enums are allowed with #[wasm_bindgen]"), diff --git a/crates/shared/src/lib.rs b/crates/shared/src/lib.rs index 57faecfcd84..969591017c8 100644 --- a/crates/shared/src/lib.rs +++ b/crates/shared/src/lib.rs @@ -109,6 +109,7 @@ macro_rules! shared_api { variant_values: Vec<&'a str>, comments: Vec<&'a str>, generate_typescript: bool, + export_type: bool, } struct Export<'a> { diff --git a/guide/src/SUMMARY.md b/guide/src/SUMMARY.md index 9ef51ede23a..644a2c26257 100644 --- a/guide/src/SUMMARY.md +++ b/guide/src/SUMMARY.md @@ -96,6 +96,7 @@ - [`getter` and `setter`](./reference/attributes/on-rust-exports/getter-and-setter.md) - [`inspectable`](./reference/attributes/on-rust-exports/inspectable.md) - [`skip_typescript`](./reference/attributes/on-rust-exports/skip_typescript.md) + - [`export_type`](./reference/attributes/on-rust-exports/export_type.md) - [`getter_with_clone`](./reference/attributes/on-rust-exports/getter_with_clone.md) - [`web-sys`](./web-sys/index.md) diff --git a/guide/src/reference/attributes/on-rust-exports/export_type.md b/guide/src/reference/attributes/on-rust-exports/export_type.md new file mode 100644 index 00000000000..d2474a40b00 --- /dev/null +++ b/guide/src/reference/attributes/on-rust-exports/export_type.md @@ -0,0 +1,84 @@ +# `export_type` + +> **Note:** This attribute is only available in `wasmbindgen` version 0.2.96 and later. + +By default, string enums do not generate any publicly exported runtime bindings and type definitions. This is done because libraries like `web-sys` can use string enums to represent specific JavaScript strings values in DOM APIs (example). If string enums were publicly exported by default, a few dozen string enum type definitions would be added to the public API of all crates that use `web-sys`. + +However, this presents the problem that you cannot make a string enum public if you want to use it in your own public API. For example: + +```rust +// your Rust code + +#[wasm_bindgen] +pub enum Status { + Success = "success", + Failure = "failure", +} + +#[wasm_bindgen] +pub fn get_status() -> Status { + Status::Success +} +``` + +```ts +// the generated TypeScript bindings + +type Status = "success" | "failure"; +export function get_status(): Status; +``` + +As you can see, a type was generated for the `Status` string enum, but the type is not publicly exported. + +While crafty users can work around this by defining their own alias (e.g. as `ReturnType`), the TypeScript API is less ergonomic because `Status` is not directly available. + +The `export_type` attribute can be used to override this behavior and make the string enum publicly exported: + +```rust +// your Rust code + +#[wasm_bindgen(export_type)] +pub enum Status { + Success = "success", + Failure = "failure", +} + +#[wasm_bindgen] +pub fn get_status() -> Status { + Status::Success +} +``` + +```ts +// the generated TypeScript bindings + +export type Status = "success" | "failure"; +export function get_status(): Status; +``` + +## Interaction with `skip_typescript` + +If you use the [`skip_typescript` attribute](./skip_typescript.md) on a string enum, the `export_type` attribute will be ignored. No type definition will be generated for the string enum. + +```rust +// your Rust code + +#[wasm_bindgen(skip_typescript, export_type)] +pub enum Status { + Success = "success", + Failure = "failure", +} + +#[wasm_bindgen] +pub fn get_status() -> Status { + Status::Success +} +``` + +```ts +// the generated TypeScript bindings + +export function get_status(): Status; +``` + +Note that this type definition has a type error, because `Status` is not defined. Using `skip_typescript` almost always requires you to define your own TypeScript types with [`typescript_custom_section`](./typescript_custom_section.md). diff --git a/guide/src/reference/attributes/on-rust-exports/index.md b/guide/src/reference/attributes/on-rust-exports/index.md index f8516caed50..a1a0077fa93 100644 --- a/guide/src/reference/attributes/on-rust-exports/index.md +++ b/guide/src/reference/attributes/on-rust-exports/index.md @@ -1,4 +1,3 @@ # `#[wasm_bindgen]` on Rust Exports -This section enumerates the attributes available for customizing bindings for -Rust functions and `struct`s exported to JavaScript. +This section enumerates the attributes available for customizing bindings for Rust functions, `struct`s, and `enum`s exported to JavaScript. From 61c880712c77be73f73868d2cbff0977c585a438 Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Sat, 9 Nov 2024 22:39:31 +0100 Subject: [PATCH 2/3] Trigger CI From 0680904d8c5fc18e51387dd97c6a04accbb62d06 Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Sat, 9 Nov 2024 22:46:08 +0100 Subject: [PATCH 3/3] Updated hash --- crates/shared/src/schema_hash_approval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/shared/src/schema_hash_approval.rs b/crates/shared/src/schema_hash_approval.rs index ebc7341bb3c..21d98de7712 100644 --- a/crates/shared/src/schema_hash_approval.rs +++ b/crates/shared/src/schema_hash_approval.rs @@ -8,7 +8,7 @@ // If the schema in this library has changed then: // 1. Bump the version in `crates/shared/Cargo.toml` // 2. Change the `SCHEMA_VERSION` in this library to this new Cargo.toml version -const APPROVED_SCHEMA_FILE_HASH: &str = "211103844299778814"; +const APPROVED_SCHEMA_FILE_HASH: &str = "11946883356319465460"; #[test] fn schema_version() {