From cfe52f98ca3bb7b93a984c51d5c83d7f5e82e884 Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Tue, 15 Oct 2024 17:53:21 +0200 Subject: [PATCH 1/6] Fixed generated types for getters and setters --- crates/cli-support/src/js/mod.rs | 236 +++++++++++++----- crates/cli/tests/reference/getter-setter.d.ts | 25 ++ crates/cli/tests/reference/getter-setter.js | 227 +++++++++++++++++ crates/cli/tests/reference/getter-setter.rs | 48 ++++ crates/cli/tests/reference/getter-setter.wat | 45 ++++ 5 files changed, 522 insertions(+), 59 deletions(-) create mode 100644 crates/cli/tests/reference/getter-setter.d.ts create mode 100644 crates/cli/tests/reference/getter-setter.js create mode 100644 crates/cli/tests/reference/getter-setter.rs create mode 100644 crates/cli/tests/reference/getter-setter.wat diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 8b8cc9aaf50..670bb050550 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -81,7 +81,7 @@ pub struct Context<'a> { } #[derive(Default)] -pub struct ExportedClass { +struct ExportedClass { comments: String, contents: String, /// The TypeScript for the class's methods. @@ -95,9 +95,29 @@ pub struct ExportedClass { is_inspectable: bool, /// All readable properties of the class readable_properties: Vec, - /// Map from field name to type as a string, docs plus whether it has a setter, - /// whether it's optional and whether it's static. - typescript_fields: HashMap, + /// Map from field to information about those fields + typescript_fields: HashMap, +} + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +struct FieldLocation { + name: String, + is_static: bool, +} +#[derive(Debug)] +struct FieldInfo { + name: String, + is_static: bool, + order: usize, + getter: Option, + setter: Option, +} +/// A getter or setter for a field. +#[derive(Debug)] +struct FieldAccessor { + ty: String, + docs: String, + is_optional: bool, } const INITIAL_HEAP_VALUES: &[&str] = &["undefined", "null", "true", "false"]; @@ -1130,27 +1150,8 @@ __wbg_set_wasm(wasm);" dst.push_str(&class.contents); ts_dst.push_str(&class.typescript); - let mut fields = class.typescript_fields.keys().collect::>(); - fields.sort(); // make sure we have deterministic output - for name in fields { - let (ty, docs, has_setter, is_optional, is_static) = &class.typescript_fields[name]; - ts_dst.push_str(docs); - ts_dst.push_str(" "); - if *is_static { - ts_dst.push_str("static "); - } - if !has_setter { - ts_dst.push_str("readonly "); - } - ts_dst.push_str(name); - if *is_optional { - ts_dst.push_str("?: "); - } else { - ts_dst.push_str(": "); - } - ts_dst.push_str(ty); - ts_dst.push_str(";\n"); - } + self.write_class_field_types(class, &mut ts_dst); + dst.push_str("}\n"); ts_dst.push_str("}\n"); @@ -1164,6 +1165,116 @@ __wbg_set_wasm(wasm);" Ok(()) } + fn write_class_field_types(&mut self, class: &ExportedClass, ts_dst: &mut String) { + let mut fields: Vec<&FieldInfo> = class.typescript_fields.values().collect(); + fields.sort_by_key(|f| f.order); // make sure we have deterministic output + + for FieldInfo { + name, + is_static, + getter, + setter, + .. + } in fields + { + let is_static = if *is_static { "static " } else { "" }; + + let write_docs = |ts_dst: &mut String, docs: &str| { + if docs.is_empty() { + return; + } + // indent by 2 spaces + for line in docs.lines() { + ts_dst.push_str(" "); + ts_dst.push_str(line); + ts_dst.push('\n'); + } + }; + let write_getter = |ts_dst: &mut String, getter: &FieldAccessor| { + write_docs(ts_dst, &getter.docs); + ts_dst.push_str(" "); + ts_dst.push_str(is_static); + ts_dst.push_str("get "); + ts_dst.push_str(name); + ts_dst.push_str("(): "); + ts_dst.push_str(&getter.ty); + ts_dst.push_str(";\n"); + }; + let write_setter = |ts_dst: &mut String, setter: &FieldAccessor| { + write_docs(ts_dst, &setter.docs); + ts_dst.push_str(" "); + ts_dst.push_str(is_static); + ts_dst.push_str("set "); + ts_dst.push_str(name); + ts_dst.push_str("(value: "); + ts_dst.push_str(&setter.ty); + if setter.is_optional { + ts_dst.push_str(" | undefined"); + } + ts_dst.push_str(");\n"); + }; + + match (getter, setter) { + (None, None) => unreachable!("field without getter or setter"), + (Some(getter), None) => { + // readonly property + write_docs(ts_dst, &getter.docs); + ts_dst.push_str(" "); + ts_dst.push_str(is_static); + ts_dst.push_str("readonly "); + ts_dst.push_str(name); + ts_dst.push_str(if getter.is_optional { "?: " } else { ": " }); + ts_dst.push_str(&getter.ty); + ts_dst.push_str(";\n"); + } + (None, Some(setter)) => { + // write-only property + + // Note: TypeScript does not handle the types of write-only + // properties correctly and will allow reads from write-only + // properties. This isn't a wasm-bindgen issue, but a + // TypeScript issue. + write_setter(ts_dst, setter); + } + (Some(getter), Some(setter)) => { + // read-write property + + // Welcome to the fun part. Okay, so we current generate + // types for optional arguments and return values differently. + // This is why for the field `foo: Option`, the setter + // will have type `T` with `is_optional` set, while the + // getter has type `T | undefined`. + // Because of this difference, we have to "normalize" the + // type of the setter. + let use_combined_property = if setter.is_optional { + getter.ty == setter.ty.clone() + " | undefined" + } else { + getter.ty == setter.ty + }; + + if use_combined_property { + // There are no good choices here, so just pick the longer comment + let docs = if getter.docs.len() > setter.docs.len() { + &getter.docs + } else { + &setter.docs + }; + write_docs(ts_dst, docs); + ts_dst.push_str(" "); + ts_dst.push_str(is_static); + ts_dst.push_str(name); + ts_dst.push_str(if setter.is_optional { "?: " } else { ": " }); + ts_dst.push_str(&setter.ty); + ts_dst.push_str(";\n"); + } else { + write_getter(ts_dst, getter); + write_setter(ts_dst, setter); + } + } + }; + } + } + fn expose_drop_ref(&mut self) { if !self.should_write_global("drop_ref") { return; @@ -2746,16 +2857,18 @@ __wbg_set_wasm(wasm);" prefix += "get "; // For getters and setters, we generate a separate TypeScript definition. if export.generate_typescript { - exported.push_accessor_ts( - &ts_docs, - name, + let location = FieldLocation { + name: name.clone(), + is_static: receiver.is_static(), + }; + let accessor = FieldAccessor { // This is only set to `None` when generating a constructor. - ts_ret_ty - .as_deref() - .expect("missing return type for getter"), - false, - receiver.is_static(), - ); + ty: ts_ret_ty.expect("missing return type for getter"), + docs: ts_docs.clone(), + is_optional: false, + }; + + exported.push_accessor_ts(location, accessor, false); } // Add the getter to the list of readable fields (used to generate `toJSON`) exported.readable_properties.push(name.clone()); @@ -2765,15 +2878,17 @@ __wbg_set_wasm(wasm);" AuxExportedMethodKind::Setter => { prefix += "set "; if export.generate_typescript { - let is_optional = exported.push_accessor_ts( - &ts_docs, - name, - &ts_arg_tys[0], - true, - receiver.is_static(), - ); - // Set whether the field is optional. - *is_optional = might_be_optional_field; + let location = FieldLocation { + name: name.clone(), + is_static: receiver.is_static(), + }; + let accessor = FieldAccessor { + ty: ts_arg_tys[0].clone(), + docs: ts_docs.clone(), + is_optional: might_be_optional_field, + }; + + exported.push_accessor_ts(location, accessor, true); } None } @@ -4414,26 +4529,29 @@ impl ExportedClass { } } - #[allow(clippy::assigning_clones)] // Clippy's suggested fix doesn't work at MSRV. fn push_accessor_ts( &mut self, - docs: &str, - field: &str, - ty: &str, + location: FieldLocation, + accessor: FieldAccessor, is_setter: bool, - is_static: bool, - ) -> &mut bool { - let (ty_dst, accessor_docs, has_setter, is_optional, is_static_dst) = - self.typescript_fields.entry(field.to_string()).or_default(); - - *ty_dst = ty.to_string(); - // Deterministic output: always use the getter's docs if available - if !docs.is_empty() && (accessor_docs.is_empty() || !is_setter) { - *accessor_docs = docs.to_owned(); + ) { + let size = self.typescript_fields.len(); + let field = self + .typescript_fields + .entry(location) + .or_insert_with_key(|location| FieldInfo { + name: location.name.to_string(), + is_static: location.is_static, + order: size, + getter: None, + setter: None, + }); + + if is_setter { + field.setter = Some(accessor); + } else { + field.getter = Some(accessor); } - *has_setter |= is_setter; - *is_static_dst = is_static; - is_optional } } diff --git a/crates/cli/tests/reference/getter-setter.d.ts b/crates/cli/tests/reference/getter-setter.d.ts new file mode 100644 index 00000000000..4c207c3c7e6 --- /dev/null +++ b/crates/cli/tests/reference/getter-setter.d.ts @@ -0,0 +1,25 @@ +/* tslint:disable */ +/* eslint-disable */ +export class Foo { + free(): void; + x: number; + y?: number; + z?: number; + readonly lone_getter: number | undefined; + set lone_setter(value: number | undefined); + /** + * You will only read numbers. + */ + get weird(): number; + /** + * But you must write strings. + * + * Yes, this is totally fine in JS. + */ + set weird(value: string | undefined); + /** + * There can be static getters and setters too, and they can even have the + * same name as instance getters and setters. + */ + static x?: boolean; +} diff --git a/crates/cli/tests/reference/getter-setter.js b/crates/cli/tests/reference/getter-setter.js new file mode 100644 index 00000000000..789dfb2787e --- /dev/null +++ b/crates/cli/tests/reference/getter-setter.js @@ -0,0 +1,227 @@ +let wasm; +export function __wbg_set_wasm(val) { + wasm = val; +} + + +const lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder; + +let cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true }); + +cachedTextDecoder.decode(); + +let cachedUint8ArrayMemory0 = null; + +function getUint8ArrayMemory0() { + if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) { + cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8ArrayMemory0; +} + +function getStringFromWasm0(ptr, len) { + ptr = ptr >>> 0; + return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len)); +} + +let cachedDataViewMemory0 = null; + +function getDataViewMemory0() { + if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) { + cachedDataViewMemory0 = new DataView(wasm.memory.buffer); + } + return cachedDataViewMemory0; +} + +function isLikeNone(x) { + return x === undefined || x === null; +} + +let WASM_VECTOR_LEN = 0; + +const lTextEncoder = typeof TextEncoder === 'undefined' ? (0, module.require)('util').TextEncoder : TextEncoder; + +let cachedTextEncoder = new lTextEncoder('utf-8'); + +const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' + ? function (arg, view) { + return cachedTextEncoder.encodeInto(arg, view); +} + : function (arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length + }; +}); + +function passStringToWasm0(arg, malloc, realloc) { + + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length, 1) >>> 0; + getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len, 1) >>> 0; + + const mem = getUint8ArrayMemory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7F) break; + mem[ptr + offset] = code; + } + + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; + const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len); + const ret = encodeString(arg, view); + + offset += ret.written; + ptr = realloc(ptr, len, offset, 1) >>> 0; + } + + WASM_VECTOR_LEN = offset; + return ptr; +} + +const FooFinalization = (typeof FinalizationRegistry === 'undefined') + ? { register: () => {}, unregister: () => {} } + : new FinalizationRegistry(ptr => wasm.__wbg_foo_free(ptr >>> 0, 1)); + +export class Foo { + + __destroy_into_raw() { + const ptr = this.__wbg_ptr; + this.__wbg_ptr = 0; + FooFinalization.unregister(this); + return ptr; + } + + free() { + const ptr = this.__destroy_into_raw(); + wasm.__wbg_foo_free(ptr, 0); + } + /** + * @returns {number} + */ + get x() { + const ret = wasm.__wbg_get_foo_x(this.__wbg_ptr); + return ret >>> 0; + } + /** + * @param {number} arg0 + */ + set x(arg0) { + wasm.__wbg_set_foo_x(this.__wbg_ptr, arg0); + } + /** + * @returns {number | undefined} + */ + get y() { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + wasm.__wbg_get_foo_y(retptr, this.__wbg_ptr); + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + return r0 === 0 ? undefined : r1 >>> 0; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } + } + /** + * @param {number | undefined} [arg0] + */ + set y(arg0) { + wasm.__wbg_set_foo_y(this.__wbg_ptr, !isLikeNone(arg0), isLikeNone(arg0) ? 0 : arg0); + } + /** + * @returns {number | undefined} + */ + get z() { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + wasm.foo_z(retptr, this.__wbg_ptr); + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + return r0 === 0 ? undefined : r1 >>> 0; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } + } + /** + * @param {number | undefined} [z] + */ + set z(z) { + wasm.foo_set_z(this.__wbg_ptr, !isLikeNone(z), isLikeNone(z) ? 0 : z); + } + /** + * @returns {number | undefined} + */ + get lone_getter() { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + wasm.foo_lone_getter(retptr, this.__wbg_ptr); + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + return r0 === 0 ? undefined : r1 >>> 0; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } + } + /** + * @param {number | undefined} [value] + */ + set lone_setter(value) { + wasm.foo_set_lone_setter(this.__wbg_ptr, !isLikeNone(value), isLikeNone(value) ? 0 : value); + } + /** + * You will only read numbers. + * @returns {number} + */ + get weird() { + const ret = wasm.foo_weird(this.__wbg_ptr); + return ret >>> 0; + } + /** + * But you must write strings. + * + * Yes, this is totally fine in JS. + * @param {string | undefined} [value] + */ + set weird(value) { + var ptr0 = isLikeNone(value) ? 0 : passStringToWasm0(value, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len0 = WASM_VECTOR_LEN; + wasm.foo_set_weird(this.__wbg_ptr, ptr0, len0); + } + /** + * There can be static getters and setters too, and they can even have the + * same name as instance getters and setters. + * @returns {boolean | undefined} + */ + static get x() { + const ret = wasm.foo_x_static(); + return ret === 0xFFFFFF ? undefined : ret !== 0; + } + /** + * @param {boolean | undefined} [value] + */ + static set x(value) { + wasm.foo_set_x_static(isLikeNone(value) ? 0xFFFFFF : value ? 1 : 0); + } +} + +export function __wbindgen_throw(arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); +}; + diff --git a/crates/cli/tests/reference/getter-setter.rs b/crates/cli/tests/reference/getter-setter.rs new file mode 100644 index 00000000000..184d34b0790 --- /dev/null +++ b/crates/cli/tests/reference/getter-setter.rs @@ -0,0 +1,48 @@ +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +struct Foo { + pub x: u32, + pub y: Option, + z: Option, +} + +#[wasm_bindgen] +impl Foo { + #[wasm_bindgen(getter)] + pub fn z(&self) -> Option { + self.z + } + #[wasm_bindgen(setter)] + pub fn set_z(&mut self, z: Option) { + self.z = z; + } + + #[wasm_bindgen(getter)] + pub fn lone_getter(&self) -> Option { + self.z + } + + #[wasm_bindgen(setter)] + pub fn set_lone_setter(&mut self, value: Option) {} + + /// You will only read numbers. + #[wasm_bindgen(getter)] + pub fn weird(&self) -> u32 { + 42 + } + /// But you must write strings. + /// + /// Yes, this is totally fine in JS. + #[wasm_bindgen(setter)] + pub fn set_weird(&mut self, value: Option) {} + + /// There can be static getters and setters too, and they can even have the + /// same name as instance getters and setters. + #[wasm_bindgen(getter = x)] + pub fn x_static() -> Option { + None + } + #[wasm_bindgen(setter = x)] + pub fn set_x_static(value: Option) {} +} diff --git a/crates/cli/tests/reference/getter-setter.wat b/crates/cli/tests/reference/getter-setter.wat new file mode 100644 index 00000000000..9688f99b7f2 --- /dev/null +++ b/crates/cli/tests/reference/getter-setter.wat @@ -0,0 +1,45 @@ +(module $reference_test.wasm + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (type (;2;) (func (param i32) (result i32))) + (type (;3;) (func (param i32 i32))) + (type (;4;) (func (param i32 i32) (result i32))) + (type (;5;) (func (param i32 i32 i32))) + (type (;6;) (func (param i32 i32 i32 i32) (result i32))) + (func $__wbindgen_realloc (;0;) (type 6) (param i32 i32 i32 i32) (result i32)) + (func $__wbindgen_malloc (;1;) (type 4) (param i32 i32) (result i32)) + (func $__wbg_set_foo_y (;2;) (type 5) (param i32 i32 i32)) + (func $__wbg_get_foo_y (;3;) (type 3) (param i32 i32)) + (func $foo_z (;4;) (type 3) (param i32 i32)) + (func $foo_lone_getter (;5;) (type 3) (param i32 i32)) + (func $foo_set_weird (;6;) (type 5) (param i32 i32 i32)) + (func $foo_set_z (;7;) (type 5) (param i32 i32 i32)) + (func $foo_set_lone_setter (;8;) (type 5) (param i32 i32 i32)) + (func $__wbg_get_foo_x (;9;) (type 2) (param i32) (result i32)) + (func $__wbg_set_foo_x (;10;) (type 3) (param i32 i32)) + (func $foo_weird (;11;) (type 2) (param i32) (result i32)) + (func $foo_x_static (;12;) (type 0) (result i32)) + (func $__wbg_foo_free (;13;) (type 3) (param i32 i32)) + (func $foo_set_x_static (;14;) (type 1) (param i32)) + (func $__wbindgen_add_to_stack_pointer (;15;) (type 2) (param i32) (result i32)) + (memory (;0;) 17) + (export "memory" (memory 0)) + (export "__wbg_foo_free" (func $__wbg_foo_free)) + (export "__wbg_get_foo_x" (func $__wbg_get_foo_x)) + (export "__wbg_set_foo_x" (func $__wbg_set_foo_x)) + (export "__wbg_get_foo_y" (func $__wbg_get_foo_y)) + (export "__wbg_set_foo_y" (func $__wbg_set_foo_y)) + (export "foo_z" (func $foo_z)) + (export "foo_set_z" (func $foo_set_z)) + (export "foo_lone_getter" (func $foo_lone_getter)) + (export "foo_set_lone_setter" (func $foo_set_lone_setter)) + (export "foo_weird" (func $foo_weird)) + (export "foo_set_weird" (func $foo_set_weird)) + (export "foo_x_static" (func $foo_x_static)) + (export "foo_set_x_static" (func $foo_set_x_static)) + (export "__wbindgen_add_to_stack_pointer" (func $__wbindgen_add_to_stack_pointer)) + (export "__wbindgen_malloc" (func $__wbindgen_malloc)) + (export "__wbindgen_realloc" (func $__wbindgen_realloc)) + (@custom "target_features" (after code) "\02+\0fmutable-globals+\08sign-ext") +) + From 79c8536d0d77a3c5b7260fbb219e1227a29e1c28 Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Tue, 15 Oct 2024 18:07:51 +0200 Subject: [PATCH 2/6] Some more comments --- crates/cli-support/src/js/mod.rs | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 670bb050550..c4164aaf7ae 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -1239,20 +1239,27 @@ __wbg_set_wasm(wasm);" (Some(getter), Some(setter)) => { // read-write property - // Welcome to the fun part. Okay, so we current generate - // types for optional arguments and return values differently. - // This is why for the field `foo: Option`, the setter - // will have type `T` with `is_optional` set, while the - // getter has type `T | undefined`. - // Because of this difference, we have to "normalize" the - // type of the setter. - let use_combined_property = if setter.is_optional { + // Here's the tricky part. The getter and setter might have + // different types. Obviously, we can only declare a + // property as `foo: T` if both the getter and setter have + // the same type `T`. If they don't, we have to declare the + // getter and setter separately. + + // We current generate types for optional arguments and + // return values differently. This is why for the field + // `foo: Option`, the setter will have type `T` with + // `is_optional` set, while the getter has type + // `T | undefined`. Because of this difference, we have to + // "normalize" the type of the setter. + let same_type = if setter.is_optional { getter.ty == setter.ty.clone() + " | undefined" } else { getter.ty == setter.ty }; - if use_combined_property { + if same_type { + // simple property, e.g. foo: T + // There are no good choices here, so just pick the longer comment let docs = if getter.docs.len() > setter.docs.len() { &getter.docs @@ -1267,6 +1274,7 @@ __wbg_set_wasm(wasm);" ts_dst.push_str(&setter.ty); ts_dst.push_str(";\n"); } else { + // separate getter and setter write_getter(ts_dst, getter); write_setter(ts_dst, setter); } From ff6a29bae4628dca4378ed195c87c325cd6c7486 Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Tue, 15 Oct 2024 18:11:52 +0200 Subject: [PATCH 3/6] Change docs strat --- crates/cli-support/src/js/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index c4164aaf7ae..d45e1e9953b 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -1260,8 +1260,8 @@ __wbg_set_wasm(wasm);" if same_type { // simple property, e.g. foo: T - // There are no good choices here, so just pick the longer comment - let docs = if getter.docs.len() > setter.docs.len() { + // Prefer the docs of the getter over the setter's + let docs = if !getter.docs.is_empty() { &getter.docs } else { &setter.docs From 7b660ebe5a02252773e672e82263c10198040fe1 Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Tue, 15 Oct 2024 21:18:51 +0200 Subject: [PATCH 4/6] Updated changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2593781fb3c..29b9b6b7baf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,12 @@ * Fixed potential `null` error when using `JsValue::as_debug_string()`. [#4192](https://github.com/rustwasm/wasm-bindgen/pull/4192) +* Fixed generated types when the getter and setter of a property had different types. + [#4202](https://github.com/rustwasm/wasm-bindgen/pull/4202) + +* Fixed generated types when a static getter/setter the same name as an instance getter/setter. + [#4202](https://github.com/rustwasm/wasm-bindgen/pull/4202) + -------------------------------------------------------------------------------- ## [0.2.95](https://github.com/rustwasm/wasm-bindgen/compare/0.2.94...0.2.95) From a1c7f5fa0b1faf2e7a740dd5c85bd9d83a370e8f Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Tue, 15 Oct 2024 23:00:39 +0200 Subject: [PATCH 5/6] Update CHANGELOG.md Co-authored-by: daxpedda --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29b9b6b7baf..7913e7b0d2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,7 @@ * Fixed generated types when the getter and setter of a property had different types. [#4202](https://github.com/rustwasm/wasm-bindgen/pull/4202) -* Fixed generated types when a static getter/setter the same name as an instance getter/setter. +* Fixed generated types when a static getter/setter has the same name as an instance getter/setter. [#4202](https://github.com/rustwasm/wasm-bindgen/pull/4202) -------------------------------------------------------------------------------- From 5307300811c0968fa76581963ac0f5e124795a39 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Wed, 16 Oct 2024 01:10:28 +0200 Subject: [PATCH 6/6] Update CHANGELOG.md Co-authored-by: daxpedda --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7913e7b0d2e..bc3fd8b1eb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ * Fixed potential `null` error when using `JsValue::as_debug_string()`. [#4192](https://github.com/rustwasm/wasm-bindgen/pull/4192) -* Fixed generated types when the getter and setter of a property had different types. +* Fixed generated types when the getter and setter of a property have different types. [#4202](https://github.com/rustwasm/wasm-bindgen/pull/4202) * Fixed generated types when a static getter/setter has the same name as an instance getter/setter.