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

Add no_export attribute and export all enums by default #4301

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
4 changes: 4 additions & 0 deletions crates/backend/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,8 @@ pub struct StringEnum {
pub rust_attrs: Vec<syn::Attribute>,
/// Whether to generate a typescript definition for this enum
pub generate_typescript: bool,
/// Whether the type should not be exported in JS/TS.
pub no_export: bool,
/// Path to wasm_bindgen
pub wasm_bindgen: Path,
}
Expand Down Expand Up @@ -467,6 +469,8 @@ pub struct Enum {
pub hole: u32,
/// Whether to generate a typescript definition for this enum
pub generate_typescript: bool,
/// Whether the type should not be exported in JS/TS.
pub no_export: bool,
/// Path to wasm_bindgen
pub wasm_bindgen: Path,
}
Expand Down
2 changes: 2 additions & 0 deletions crates/backend/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ fn shared_enum<'a>(e: &'a ast::Enum, intern: &'a Interner) -> Enum<'a> {
.collect(),
comments: e.comments.iter().map(|s| &**s).collect(),
generate_typescript: e.generate_typescript,
no_export: e.no_export,
}
}

Expand Down Expand Up @@ -364,6 +365,7 @@ fn shared_import_enum<'a>(i: &'a ast::StringEnum, _intern: &'a Interner) -> Stri
StringEnum {
name: &i.js_name,
generate_typescript: i.generate_typescript,
no_export: i.no_export,
variant_values: i.variant_values.iter().map(|x| &**x).collect(),
comments: i.comments.iter().map(|s| &**s).collect(),
}
Expand Down
9 changes: 8 additions & 1 deletion crates/cli-support/src/js/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ pub struct JsFunction {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum TsReference {
StringEnum(String),
Enum(String),
}

impl<'a, 'b> Builder<'a, 'b> {
Expand Down Expand Up @@ -1570,7 +1571,13 @@ fn adapter2ts(ty: &AdapterType, dst: &mut String, refs: Option<&mut HashSet<TsRe
}
AdapterType::NamedExternref(name) => dst.push_str(name),
AdapterType::Struct(name) => dst.push_str(name),
AdapterType::Enum(name) => dst.push_str(name),
AdapterType::Enum(name) => {
if let Some(refs) = refs {
refs.insert(TsReference::Enum(name.clone()));
}

dst.push_str(name)
}
AdapterType::StringEnum(name) => {
if let Some(refs) = refs {
refs.insert(TsReference::StringEnum(name.clone()));
Expand Down
62 changes: 38 additions & 24 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3915,12 +3915,21 @@ __wbg_set_wasm(wasm);"
fn generate_enum(&mut self, enum_: &AuxEnum) -> Result<(), Error> {
let mut variants = String::new();

if enum_.generate_typescript {
let is_used_in_typescript = self
.typescript_refs
.contains(&TsReference::Enum(enum_.name.clone()));

let ts = enum_.generate_typescript && (!enum_.no_export || is_used_in_typescript);

if ts {
self.typescript
.push_str(&format_doc_comments(&enum_.comments, None));
self.typescript
.push_str(&format!("export enum {} {{", enum_.name));
if !enum_.no_export {
self.typescript.push_str("export ");
}
self.typescript.push_str(&format!("enum {} {{", enum_.name));
}

for (name, value, comments) in enum_.variants.iter() {
let variant_docs = if comments.is_empty() {
String::new()
Expand All @@ -3930,7 +3939,7 @@ __wbg_set_wasm(wasm);"
variants.push_str(&variant_docs);
variants.push_str(&format!("{}: {}, ", name, value));
variants.push_str(&format!("\"{}\": \"{}\",\n", value, name));
if enum_.generate_typescript {
if ts {
self.typescript.push('\n');
if !variant_docs.is_empty() {
for line in variant_docs.lines() {
Expand All @@ -3942,26 +3951,28 @@ __wbg_set_wasm(wasm);"
self.typescript.push_str(&format!(" {name} = {value},"));
}
}
if enum_.generate_typescript {
if ts {
self.typescript.push_str("\n}\n");
}

// add an `@enum {1 | 2 | 3}` to ensure that enums type-check even without .d.ts
let mut at_enum = "@enum {".to_string();
for (i, (_, value, _)) in enum_.variants.iter().enumerate() {
if i != 0 {
at_enum.push_str(" | ");
if !enum_.no_export {
// add an `@enum {1 | 2 | 3}` to ensure that enums type-check even without .d.ts
let mut at_enum = "@enum {".to_string();
for (i, (_, value, _)) in enum_.variants.iter().enumerate() {
if i != 0 {
at_enum.push_str(" | ");
}
at_enum.push_str(&value.to_string());
}
at_enum.push_str(&value.to_string());
}
at_enum.push('}');
let docs = format_doc_comments(&enum_.comments, Some(at_enum));
at_enum.push('}');
let docs = format_doc_comments(&enum_.comments, Some(at_enum));

self.export(
&enum_.name,
&format!("Object.freeze({{\n{}}})", variants),
Some(&docs),
)?;
self.export(
&enum_.name,
&format!("Object.freeze({{\n{}}})", variants),
Some(&docs),
)?;
}

Ok(())
}
Expand All @@ -3973,11 +3984,11 @@ __wbg_set_wasm(wasm);"
.map(|v| format!("\"{v}\""))
.collect();

if string_enum.generate_typescript
&& self
.typescript_refs
.contains(&TsReference::StringEnum(string_enum.name.clone()))
{
let is_used_in_typescript = self
.typescript_refs
.contains(&TsReference::StringEnum(string_enum.name.clone()));

if string_enum.generate_typescript && (!string_enum.no_export || is_used_in_typescript) {
let docs = format_doc_comments(&string_enum.comments, None);
let type_expr = if variants.is_empty() {
"never".to_string()
Expand All @@ -3986,6 +3997,9 @@ __wbg_set_wasm(wasm);"
};

self.typescript.push_str(&docs);
if !string_enum.no_export {
self.typescript.push_str("export ");
}
self.typescript.push_str("type ");
self.typescript.push_str(&string_enum.name);
self.typescript.push_str(" = ");
Expand Down
2 changes: 2 additions & 0 deletions crates/cli-support/src/wit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,7 @@ impl<'a> Context<'a> {
.map(|v| v.to_string())
.collect(),
generate_typescript: string_enum.generate_typescript,
no_export: string_enum.no_export,
};
let mut result = Ok(());
self.aux
Expand Down Expand Up @@ -909,6 +910,7 @@ impl<'a> Context<'a> {
})
.collect(),
generate_typescript: enum_.generate_typescript,
no_export: enum_.no_export,
};
let mut result = Ok(());
self.aux
Expand Down
4 changes: 4 additions & 0 deletions crates/cli-support/src/wit/nonstandard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ pub struct AuxEnum {
pub variants: Vec<(String, i64, String)>,
/// Whether typescript bindings should be generated for this enum.
pub generate_typescript: bool,
/// Whether the type should not be exported in JS/TS.
pub no_export: bool,
}

#[derive(Debug)]
Expand All @@ -185,6 +187,8 @@ pub struct AuxStringEnum {
pub variant_values: Vec<String>,
/// Whether typescript bindings should be generated for this enum.
pub generate_typescript: bool,
/// Whether the type should not be exported in JS/TS.
pub no_export: bool,
}

#[derive(Debug)]
Expand Down
17 changes: 16 additions & 1 deletion crates/cli/tests/reference/enums.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export function enum_echo(color: Color): Color;
export function option_enum_echo(color?: Color): Color | undefined;
export function get_name(color: Color): ColorName;
export function option_string_enum_echo(color?: ColorName): ColorName | undefined;
export function use_used(arg0: NoExportButUsedStringEnum, arg1: NoExportButUsedEnum): void;
export function option_order(order?: Ordering): Ordering | undefined;
/**
* A color.
Expand All @@ -28,6 +29,10 @@ export enum ImplicitDiscriminant {
C = 42,
D = 43,
}
enum NoExportButUsedEnum {
Foo = 0,
Bar = 1,
}
/**
* A C-style enum with negative discriminants.
*/
Expand All @@ -36,7 +41,17 @@ export enum Ordering {
Equal = 0,
Greater = 1,
}
export enum PrivateEnum {
Foo = 0,
Bar = 1,
}
/**
* The name of a color.
*/
type ColorName = "green" | "yellow" | "red";
export type ColorName = "green" | "yellow" | "red";
/**
* An unused string enum.
*/
export type FooBar = "foo" | "bar";
type NoExportButUsedStringEnum = "foo" | "bar";
export type PrivateStringEnum = "foo" | "bar";
17 changes: 17 additions & 0 deletions crates/cli/tests/reference/enums.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ export function option_string_enum_echo(color) {
return __wbindgen_enum_ColorName[ret];
}

/**
* @param {NoExportButUsedStringEnum} arg0
* @param {NoExportButUsedEnum} arg1
*/
export function use_used(arg0, arg1) {
wasm.use_used((__wbindgen_enum_NoExportButUsedStringEnum.indexOf(arg0) + 1 || 3) - 1, arg1);
}

/**
* @param {Ordering | undefined} [order]
* @returns {Ordering | undefined}
Expand Down Expand Up @@ -107,9 +115,18 @@ export const Ordering = Object.freeze({
Equal: 0, "0": "Equal",
Greater: 1, "1": "Greater",
});
/**
* @enum {0 | 1}
*/
export const PrivateEnum = Object.freeze({
Foo: 0, "0": "Foo",
Bar: 1, "1": "Bar",
});

const __wbindgen_enum_ColorName = ["green", "yellow", "red"];

const __wbindgen_enum_NoExportButUsedStringEnum = ["foo", "bar"];

export function __wbindgen_init_externref_table() {
const table = wasm.__wbindgen_export_0;
const offset = table.grow(4);
Expand Down
30 changes: 30 additions & 0 deletions crates/cli/tests/reference/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,36 @@ enum PrivateStringEnum {
Foo = "foo",
Bar = "bar",
}
#[wasm_bindgen]
enum PrivateEnum {
Foo,
Bar,
}

#[wasm_bindgen(no_export)]
pub enum NoExportStringEnum {
Foo = "foo",
Bar = "bar",
}
#[wasm_bindgen(no_export)]
pub enum NoExportEnum {
Foo,
Bar,
}

#[wasm_bindgen(no_export)]
pub enum NoExportButUsedStringEnum {
Foo = "foo",
Bar = "bar",
}
#[wasm_bindgen(no_export)]
pub enum NoExportButUsedEnum {
Foo,
Bar,
}

#[wasm_bindgen]
pub fn use_used(arg0: NoExportButUsedStringEnum, arg1: NoExportButUsedEnum) {}

#[wasm_bindgen]
pub enum ImplicitDiscriminant {
Expand Down
13 changes: 8 additions & 5 deletions crates/cli/tests/reference/enums.wat
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
(module $reference_test.wasm
(type (;0;) (func))
(type (;1;) (func (param i32) (result i32)))
(type (;2;) (func (param i32 i32)))
(import "./reference_test_bg.js" "__wbindgen_init_externref_table" (func (;0;) (type 0)))
(func $enum_echo (;1;) (type 1) (param i32) (result i32))
(func $option_enum_echo (;2;) (type 1) (param i32) (result i32))
(func $get_name (;3;) (type 1) (param i32) (result i32))
(func $option_string_enum_echo (;4;) (type 1) (param i32) (result i32))
(func $option_order (;5;) (type 1) (param i32) (result i32))
(func $use_used (;1;) (type 2) (param i32 i32))
(func $enum_echo (;2;) (type 1) (param i32) (result i32))
(func $option_enum_echo (;3;) (type 1) (param i32) (result i32))
(func $get_name (;4;) (type 1) (param i32) (result i32))
(func $option_string_enum_echo (;5;) (type 1) (param i32) (result i32))
(func $option_order (;6;) (type 1) (param i32) (result i32))
(table (;0;) 128 externref)
(memory (;0;) 17)
(export "memory" (memory 0))
(export "enum_echo" (func $enum_echo))
(export "option_enum_echo" (func $option_enum_echo))
(export "get_name" (func $get_name))
(export "option_string_enum_echo" (func $option_string_enum_echo))
(export "use_used" (func $use_used))
(export "option_order" (func $option_order))
(export "__wbindgen_export_0" (table 0))
(export "__wbindgen_start" (func 0))
Expand Down
19 changes: 13 additions & 6 deletions crates/macro-support/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ macro_rules! attrgen {
(js_sys, JsSys(Span, syn::Path)),
(wasm_bindgen_futures, WasmBindgenFutures(Span, syn::Path)),
(skip, Skip(Span)),
(no_export, NoExport(Span)),
(typescript_type, TypeScriptType(Span, String, Span)),
(getter_with_clone, GetterWithClone(Span)),
(static_string, StaticString(Span)),
Expand Down Expand Up @@ -1375,6 +1376,7 @@ fn string_enum(
program: &mut ast::Program,
js_name: String,
generate_typescript: bool,
no_export: bool,
comments: Vec<String>,
) -> Result<(), Diagnostic> {
let mut variants = vec![];
Expand Down Expand Up @@ -1414,6 +1416,7 @@ fn string_enum(
comments,
rust_attrs: enum_.attrs,
generate_typescript,
no_export,
wasm_bindgen: program.wasm_bindgen.clone(),
}),
});
Expand Down Expand Up @@ -1481,6 +1484,7 @@ impl<'a> MacroParse<(&'a mut TokenStream, BindgenAttrs)> for syn::ItemEnum {
}

let generate_typescript = opts.skip_typescript().is_none();
let no_export = opts.no_export().is_some();
let js_name = opts
.js_name()
.map(|s| s.0)
Expand All @@ -1503,12 +1507,14 @@ 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);
}

match self.vis {
syn::Visibility::Public(_) => {}
_ => bail_span!(self, "only public enums are allowed with #[wasm_bindgen]"),
return string_enum(
self,
program,
js_name,
generate_typescript,
no_export,
comments,
);
}

// Go through all variants once first to determine whether the enum is
Expand Down Expand Up @@ -1613,6 +1619,7 @@ impl<'a> MacroParse<(&'a mut TokenStream, BindgenAttrs)> for syn::ItemEnum {
comments,
hole,
generate_typescript,
no_export,
wasm_bindgen: program.wasm_bindgen.clone(),
});
Ok(())
Expand Down
Loading